@deepstrike/sdk 0.1.10 → 0.1.12

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 (40) hide show
  1. package/README.md +25 -0
  2. package/dist/agent.d.ts +10 -9
  3. package/dist/agent.js +64 -12
  4. package/dist/collaboration/contract.d.ts +55 -0
  5. package/dist/collaboration/contract.js +65 -0
  6. package/dist/collaboration/handoff.d.ts +79 -0
  7. package/dist/collaboration/handoff.js +98 -0
  8. package/dist/collaboration/harness.d.ts +55 -0
  9. package/dist/collaboration/harness.js +150 -0
  10. package/dist/collaboration/index.d.ts +10 -0
  11. package/dist/collaboration/index.js +9 -0
  12. package/dist/collaboration/modes/creator-verifier.d.ts +69 -0
  13. package/dist/collaboration/modes/creator-verifier.js +124 -0
  14. package/dist/collaboration/pool.d.ts +46 -0
  15. package/dist/collaboration/pool.js +80 -0
  16. package/dist/harness/harness.js +7 -1
  17. package/dist/index.d.ts +12 -2
  18. package/dist/index.js +5 -0
  19. package/dist/kernel.d.ts +5 -2
  20. package/dist/memory/protocols.d.ts +8 -1
  21. package/dist/providers/anthropic.d.ts +3 -3
  22. package/dist/providers/anthropic.js +9 -9
  23. package/dist/providers/base.d.ts +7 -4
  24. package/dist/providers/base.js +41 -38
  25. package/dist/providers/deepseek.d.ts +2 -2
  26. package/dist/providers/deepseek.js +2 -2
  27. package/dist/providers/gemini.d.ts +3 -3
  28. package/dist/providers/gemini.js +8 -13
  29. package/dist/providers/ollama.d.ts +3 -3
  30. package/dist/providers/ollama.js +12 -8
  31. package/dist/providers/openai-chat.d.ts +2 -2
  32. package/dist/providers/openai-chat.js +6 -4
  33. package/dist/providers/openai-responses.d.ts +5 -5
  34. package/dist/providers/openai-responses.js +13 -19
  35. package/dist/providers/openai.d.ts +3 -3
  36. package/dist/providers/openai.js +4 -4
  37. package/dist/providers/qwen.d.ts +3 -3
  38. package/dist/providers/qwen.js +4 -4
  39. package/dist/types.d.ts +12 -2
  40. package/package.json +2 -2
@@ -1,3 +1,4 @@
1
+ import type { Message, RenderedContext } from "../types.js";
1
2
  export declare class CircuitBreaker {
2
3
  private readonly openAfter;
3
4
  private readonly resetAfter;
@@ -13,9 +14,11 @@ export declare function normalizeToolCall(id: string, name: string, args: unknow
13
14
  name: string;
14
15
  arguments: string;
15
16
  } | null;
16
- import type { Message } from "../types.js";
17
17
  export declare function toAnthropicContent(msg: Message): string | Array<Record<string, unknown>>;
18
+ /** Convert RenderedContext.turns to Anthropic messages array.
19
+ * `turns` contains only user / assistant / tool roles — no system filtering needed. */
20
+ export declare function toAnthropicMessages(turns: Message[], nativeReplay?: (message: Message) => Array<Record<string, unknown>> | undefined): Array<Record<string, unknown>>;
18
21
  export declare function toOpenAIContent(msg: Message): string | Array<Record<string, unknown>>;
19
- export declare function splitAnthropicSystem(messages: Message[]): string;
20
- export declare function toAnthropicMessages(messages: Message[], nativeReplay?: (message: Message) => Array<Record<string, unknown>> | undefined): Array<Record<string, unknown>>;
21
- export declare function toOpenAIMessageParams(messages: Message[]): Array<Record<string, unknown>>;
22
+ /** Build the full OpenAI messages array from a RenderedContext.
23
+ * Prepends systemText as the first system message, then converts turns. */
24
+ export declare function toOpenAIMessageParams(context: RenderedContext): Array<Record<string, unknown>>;
@@ -44,6 +44,15 @@ export function normalizeToolCall(id, name, args) {
44
44
  }
45
45
  return { id: String(id ?? ""), name: n, arguments: JSON.stringify(parsed) };
46
46
  }
47
+ function parseToolArguments(args) {
48
+ try {
49
+ return JSON.parse(args || "{}");
50
+ }
51
+ catch {
52
+ return {};
53
+ }
54
+ }
55
+ // ─── Anthropic message conversion ────────────────────────────────────────────
47
56
  export function toAnthropicContent(msg) {
48
57
  if (!msg.contentParts?.length)
49
58
  return msg.content;
@@ -65,39 +74,11 @@ export function toAnthropicContent(msg) {
65
74
  return { type: "text", text: "" };
66
75
  });
67
76
  }
68
- export function toOpenAIContent(msg) {
69
- if (!msg.contentParts?.length)
70
- return msg.content;
71
- return msg.contentParts.map(p => {
72
- if (p.type === "text")
73
- return { type: "text", text: p.text };
74
- if (p.type === "image") {
75
- const url = p.data ? `data:${p.mediaType ?? "image/png"};base64,${p.data}` : p.url;
76
- return { type: "image_url", image_url: { url, ...(p.detail ? { detail: p.detail } : {}) } };
77
- }
78
- if (p.type === "audio") {
79
- return { type: "input_audio", input_audio: { data: p.data, format: p.mediaType?.split("/")[1] ?? "wav" } };
80
- }
81
- if (p.type === "tool_result") {
82
- return { type: "text", text: p.output };
83
- }
84
- return { type: "text", text: "" };
85
- });
86
- }
87
- function parseToolArguments(args) {
88
- try {
89
- return JSON.parse(args || "{}");
90
- }
91
- catch {
92
- return {};
93
- }
94
- }
95
- export function splitAnthropicSystem(messages) {
96
- return messages.filter(m => m.role === "system").map(m => m.content).join("\n\n");
97
- }
98
- export function toAnthropicMessages(messages, nativeReplay) {
77
+ /** Convert RenderedContext.turns to Anthropic messages array.
78
+ * `turns` contains only user / assistant / tool roles — no system filtering needed. */
79
+ export function toAnthropicMessages(turns, nativeReplay) {
99
80
  const result = [];
100
- for (const msg of messages.filter(m => m.role !== "system")) {
81
+ for (const msg of turns) {
101
82
  if (msg.role === "tool") {
102
83
  const parts = (msg.contentParts ?? [])
103
84
  .filter((p) => p.type === "tool_result")
@@ -124,16 +105,38 @@ export function toAnthropicMessages(messages, nativeReplay) {
124
105
  result.push({ role: "assistant", content: blocks });
125
106
  continue;
126
107
  }
127
- result.push({
128
- role: msg.role,
129
- content: toAnthropicContent(msg),
130
- });
108
+ result.push({ role: msg.role, content: toAnthropicContent(msg) });
131
109
  }
132
110
  return result;
133
111
  }
134
- export function toOpenAIMessageParams(messages) {
112
+ // ─── OpenAI-compatible message conversion ────────────────────────────────────
113
+ export function toOpenAIContent(msg) {
114
+ if (!msg.contentParts?.length)
115
+ return msg.content;
116
+ return msg.contentParts.map(p => {
117
+ if (p.type === "text")
118
+ return { type: "text", text: p.text };
119
+ if (p.type === "image") {
120
+ const url = p.data ? `data:${p.mediaType ?? "image/png"};base64,${p.data}` : p.url;
121
+ return { type: "image_url", image_url: { url, ...(p.detail ? { detail: p.detail } : {}) } };
122
+ }
123
+ if (p.type === "audio") {
124
+ return { type: "input_audio", input_audio: { data: p.data, format: p.mediaType?.split("/")[1] ?? "wav" } };
125
+ }
126
+ if (p.type === "tool_result") {
127
+ return { type: "text", text: p.output };
128
+ }
129
+ return { type: "text", text: "" };
130
+ });
131
+ }
132
+ /** Build the full OpenAI messages array from a RenderedContext.
133
+ * Prepends systemText as the first system message, then converts turns. */
134
+ export function toOpenAIMessageParams(context) {
135
135
  const result = [];
136
- for (const msg of messages) {
136
+ if (context.systemText) {
137
+ result.push({ role: "system", content: context.systemText });
138
+ }
139
+ for (const msg of context.turns) {
137
140
  if (msg.role === "tool") {
138
141
  const parts = (msg.contentParts ?? [])
139
142
  .filter((p) => p.type === "tool_result");
@@ -1,9 +1,9 @@
1
- import type { Message, ToolSchema, StreamEvent } from "../types.js";
1
+ import type { RenderedContext, ToolSchema, StreamEvent } from "../types.js";
2
2
  import { OpenAIChatProvider } from "./openai.js";
3
3
  export declare class DeepSeekProvider extends OpenAIChatProvider {
4
4
  constructor(apiKey: string, model?: "deepseek-v4-flash" | "deepseek-v4-pro", retry?: {
5
5
  maxRetries: number;
6
6
  baseDelay: number;
7
7
  }, baseURL?: string);
8
- stream(messages: Message[], tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
8
+ stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
9
9
  }
@@ -5,11 +5,11 @@ export class DeepSeekProvider extends OpenAIChatProvider {
5
5
  constructor(apiKey, model = "deepseek-v4-flash", retry, baseURL = DEEPSEEK_BASE) {
6
6
  super(apiKey, model, retry, baseURL);
7
7
  }
8
- async *stream(messages, tools, extensions) {
8
+ async *stream(context, tools, extensions) {
9
9
  const exposeReasoning = extensions?.exposeReasoning ?? false;
10
10
  const thinking = extensions?.thinking === false ? "disabled" : "enabled";
11
11
  const reasoningEffort = extensions?.reasoningEffort === "max" ? "max" : "high";
12
- const msgs = this.chat.buildMessages(messages);
12
+ const msgs = this.chat.buildMessages(context);
13
13
  const toolCallBufs = {};
14
14
  let reasoningContent = "";
15
15
  let finalText = "";
@@ -1,4 +1,4 @@
1
- import type { Message, ToolSchema, StreamEvent, LLMProvider } from "../types.js";
1
+ import type { Message, RenderedContext, ToolSchema, StreamEvent, LLMProvider } from "../types.js";
2
2
  export declare class GeminiProvider implements LLMProvider {
3
3
  private readonly model;
4
4
  private genAI;
@@ -9,6 +9,6 @@ export declare class GeminiProvider implements LLMProvider {
9
9
  maxRetries: number;
10
10
  baseDelay: number;
11
11
  }, baseURL?: string);
12
- complete(messages: Message[], tools: ToolSchema[]): Promise<Message>;
13
- stream(messages: Message[], tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
12
+ complete(context: RenderedContext, tools: ToolSchema[]): Promise<Message>;
13
+ stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
14
14
  }
@@ -3,11 +3,9 @@ import { withServerRuntimeGuard } from "../runtime/server.js";
3
3
  import { CircuitBreaker, normalizeToolCall } from "./base.js";
4
4
  import { endpointProfiles } from "./profiles.js";
5
5
  const GEMINI_BASE = endpointProfiles["gemini.google"].baseURL;
6
- function buildContents(messages) {
6
+ function buildContents(turns) {
7
7
  const contents = [];
8
- for (const msg of messages) {
9
- if (msg.role === "system")
10
- continue;
8
+ for (const msg of turns) {
11
9
  if (msg.role === "tool") {
12
10
  const parts = (msg.contentParts ?? [])
13
11
  .filter(p => p.type === "tool_result")
@@ -50,9 +48,6 @@ function buildTools(tools) {
50
48
  })),
51
49
  }];
52
50
  }
53
- function systemInstruction(messages) {
54
- return messages.find(m => m.role === "system")?.content;
55
- }
56
51
  export class GeminiProvider {
57
52
  model;
58
53
  genAI;
@@ -66,11 +61,11 @@ export class GeminiProvider {
66
61
  this.maxRetries = retry.maxRetries;
67
62
  this.baseDelay = retry.baseDelay;
68
63
  }
69
- async complete(messages, tools) {
64
+ async complete(context, tools) {
70
65
  if (this.circuit.isOpen())
71
66
  throw new Error("Circuit breaker open");
72
- const system = systemInstruction(messages);
73
- const contents = buildContents(messages);
67
+ const system = context.systemText || undefined;
68
+ const contents = buildContents(context.turns);
74
69
  const geminiTools = buildTools(tools);
75
70
  let lastErr;
76
71
  for (let i = 0; i < this.maxRetries; i++) {
@@ -111,9 +106,9 @@ export class GeminiProvider {
111
106
  }
112
107
  throw lastErr;
113
108
  }
114
- async *stream(messages, tools, extensions) {
115
- const system = systemInstruction(messages);
116
- const contents = buildContents(messages);
109
+ async *stream(context, tools, extensions) {
110
+ const system = context.systemText || undefined;
111
+ const contents = buildContents(context.turns);
117
112
  const geminiTools = buildTools(tools);
118
113
  const m = this.genAI.getGenerativeModel({
119
114
  model: this.model,
@@ -1,9 +1,9 @@
1
- import type { Message, ToolSchema, StreamEvent, LLMProvider } from "../types.js";
1
+ import type { Message, RenderedContext, ToolSchema, StreamEvent, LLMProvider } from "../types.js";
2
2
  export declare class OllamaProvider implements LLMProvider {
3
3
  private readonly model;
4
4
  private readonly baseUrl;
5
5
  constructor(model?: string, baseUrl?: string);
6
6
  private toOllamaMessages;
7
- complete(messages: Message[], tools: ToolSchema[]): Promise<Message>;
8
- stream(messages: Message[], tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
7
+ complete(context: RenderedContext, tools: ToolSchema[]): Promise<Message>;
8
+ stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
9
9
  }
@@ -6,8 +6,11 @@ export class OllamaProvider {
6
6
  this.model = model;
7
7
  this.baseUrl = baseUrl;
8
8
  }
9
- toOllamaMessages(messages) {
10
- return messages.map(m => {
9
+ toOllamaMessages(context) {
10
+ const result = [];
11
+ if (context.systemText)
12
+ result.push({ role: "system", content: context.systemText });
13
+ for (const m of context.turns) {
11
14
  const images = [];
12
15
  if (m.contentParts?.length) {
13
16
  for (const p of m.contentParts) {
@@ -15,25 +18,26 @@ export class OllamaProvider {
15
18
  images.push(p.data);
16
19
  }
17
20
  }
18
- return { role: m.role, content: m.content, ...(images.length ? { images } : {}) };
19
- });
21
+ result.push({ role: m.role, content: m.content, ...(images.length ? { images } : {}) });
22
+ }
23
+ return result;
20
24
  }
21
- async complete(messages, tools) {
25
+ async complete(context, tools) {
22
26
  const resp = await fetch(`${this.baseUrl}/api/chat`, {
23
27
  method: "POST",
24
28
  headers: { "Content-Type": "application/json" },
25
- body: JSON.stringify({ model: this.model, messages: this.toOllamaMessages(messages), stream: false }),
29
+ body: JSON.stringify({ model: this.model, messages: this.toOllamaMessages(context), stream: false }),
26
30
  });
27
31
  if (!resp.ok)
28
32
  throw new Error(`Ollama error: ${resp.status}`);
29
33
  const data = await resp.json();
30
34
  return { role: "assistant", content: data.message.content };
31
35
  }
32
- async *stream(messages, tools, extensions) {
36
+ async *stream(context, tools, extensions) {
33
37
  const resp = await fetch(`${this.baseUrl}/api/chat`, {
34
38
  method: "POST",
35
39
  headers: { "Content-Type": "application/json" },
36
- body: JSON.stringify({ model: this.model, messages: this.toOllamaMessages(messages), stream: true }),
40
+ body: JSON.stringify({ model: this.model, messages: this.toOllamaMessages(context), stream: true }),
37
41
  });
38
42
  if (!resp.ok)
39
43
  throw new Error(`Ollama error: ${resp.status}`);
@@ -1,5 +1,5 @@
1
1
  import type OpenAI from "openai";
2
- import type { Message, ToolSchema } from "../types.js";
2
+ import type { Message, RenderedContext, ToolSchema } from "../types.js";
3
3
  export declare class OpenAIChatAdapter {
4
4
  private replayFields;
5
5
  buildTools(tools: ToolSchema[]): {
@@ -10,7 +10,7 @@ export declare class OpenAIChatAdapter {
10
10
  parameters: any;
11
11
  };
12
12
  }[];
13
- buildMessages(messages: Message[]): OpenAI.ChatCompletionMessageParam[];
13
+ buildMessages(context: RenderedContext): OpenAI.ChatCompletionMessageParam[];
14
14
  normalizeToolCalls(toolCalls?: Array<{
15
15
  id: string;
16
16
  function: {
@@ -7,10 +7,12 @@ export class OpenAIChatAdapter {
7
7
  function: { name: t.name, description: t.description, parameters: JSON.parse(t.parameters) },
8
8
  }));
9
9
  }
10
- buildMessages(messages) {
11
- const serialized = toOpenAIMessageParams(messages);
12
- let cursor = 0;
13
- for (const source of messages) {
10
+ buildMessages(context) {
11
+ // toOpenAIMessageParams prepends systemText as messages[0], then turns.
12
+ const serialized = toOpenAIMessageParams(context);
13
+ // Cursor starts at 1 to skip the system message injected by toOpenAIMessageParams.
14
+ let cursor = context.systemText ? 1 : 0;
15
+ for (const source of context.turns) {
14
16
  if (source.role === "tool") {
15
17
  cursor += (source.contentParts ?? []).filter(p => p.type === "tool_result").length;
16
18
  continue;
@@ -1,5 +1,5 @@
1
1
  import OpenAI from "openai";
2
- import type { Message, ProviderRunState, StreamEvent, ToolSchema, LLMProvider } from "../types.js";
2
+ import type { Message, ProviderRunState, RenderedContext, StreamEvent, ToolSchema, LLMProvider } from "../types.js";
3
3
  import { CircuitBreaker } from "./base.js";
4
4
  export interface OpenAIResponsesRunState extends ProviderRunState {
5
5
  previousResponseId?: string;
@@ -12,8 +12,8 @@ export declare class OpenAIResponsesAdapter {
12
12
  description: string;
13
13
  parameters: any;
14
14
  }[];
15
- buildInstructions(messages: Message[]): string | undefined;
16
- buildInput(messages: Message[], state?: OpenAIResponsesRunState): Array<Record<string, unknown>>;
15
+ buildInstructions(context: RenderedContext): string | undefined;
16
+ buildInput(context: RenderedContext, state?: OpenAIResponsesRunState): Array<Record<string, unknown>>;
17
17
  decodeOutput(output: Array<Record<string, unknown>>): {
18
18
  content: string;
19
19
  toolCalls: Array<{
@@ -36,7 +36,7 @@ export declare class OpenAIResponsesProvider implements LLMProvider {
36
36
  baseDelay: number;
37
37
  }, baseURL?: string);
38
38
  createRunState(): OpenAIResponsesRunState;
39
- complete(messages: Message[], tools: ToolSchema[]): Promise<Message>;
40
- stream(messages: Message[], tools: ToolSchema[], _extensions?: Record<string, unknown>, state?: ProviderRunState): AsyncIterable<StreamEvent>;
39
+ complete(context: RenderedContext, tools: ToolSchema[]): Promise<Message>;
40
+ stream(context: RenderedContext, tools: ToolSchema[], _extensions?: Record<string, unknown>, state?: ProviderRunState): AsyncIterable<StreamEvent>;
41
41
  private asRunState;
42
42
  }
@@ -11,22 +11,16 @@ export class OpenAIResponsesAdapter {
11
11
  parameters: JSON.parse(t.parameters),
12
12
  }));
13
13
  }
14
- buildInstructions(messages) {
15
- const instructions = messages
16
- .filter(message => message.role === "system")
17
- .map(message => message.content)
18
- .filter(Boolean);
19
- return instructions.length ? instructions.join("\n\n") : undefined;
14
+ buildInstructions(context) {
15
+ return context.systemText || undefined;
20
16
  }
21
- buildInput(messages, state) {
17
+ buildInput(context, state) {
22
18
  const input = [];
19
+ const turns = context.turns;
23
20
  const uncoveredMessages = state?.previousResponseId
24
- ? messages.slice(state.coveredMessageCount)
25
- : messages;
21
+ ? turns.slice(state.coveredMessageCount)
22
+ : turns;
26
23
  for (const message of uncoveredMessages) {
27
- if (message.role === "system") {
28
- continue;
29
- }
30
24
  if (message.role === "assistant" && message.toolCalls?.length) {
31
25
  if (message.content || message.contentParts?.length) {
32
26
  input.push({
@@ -122,16 +116,16 @@ export class OpenAIResponsesProvider {
122
116
  createRunState() {
123
117
  return { coveredMessageCount: 0 };
124
118
  }
125
- async complete(messages, tools) {
119
+ async complete(context, tools) {
126
120
  if (this.circuit.isOpen())
127
121
  throw new Error("Circuit breaker open");
128
122
  let lastErr;
129
123
  for (let i = 0; i < this.maxRetries; i++) {
130
124
  try {
131
- const instructions = this.responses.buildInstructions(messages);
125
+ const instructions = this.responses.buildInstructions(context);
132
126
  const resp = await this.client.responses.create({
133
127
  model: this.model,
134
- input: this.responses.buildInput(messages),
128
+ input: this.responses.buildInput(context),
135
129
  ...(instructions ? { instructions } : {}),
136
130
  ...(tools.length ? { tools: this.responses.buildTools(tools) } : {}),
137
131
  });
@@ -153,13 +147,13 @@ export class OpenAIResponsesProvider {
153
147
  }
154
148
  throw lastErr;
155
149
  }
156
- async *stream(messages, tools, _extensions, state) {
150
+ async *stream(context, tools, _extensions, state) {
157
151
  const runState = this.asRunState(state);
158
152
  const functionCalls = new Map();
159
- const instructions = this.responses.buildInstructions(messages);
153
+ const instructions = this.responses.buildInstructions(context);
160
154
  const stream = await this.client.responses.create({
161
155
  model: this.model,
162
- input: this.responses.buildInput(messages, runState),
156
+ input: this.responses.buildInput(context, runState),
163
157
  ...(instructions ? { instructions } : {}),
164
158
  ...(runState.previousResponseId ? { previous_response_id: runState.previousResponseId } : {}),
165
159
  ...(tools.length ? { tools: this.responses.buildTools(tools) } : {}),
@@ -203,7 +197,7 @@ export class OpenAIResponsesProvider {
203
197
  }
204
198
  else if (evt.type === "response.completed") {
205
199
  runState.previousResponseId = evt.response.id;
206
- runState.coveredMessageCount = messages.length + 1;
200
+ runState.coveredMessageCount = context.turns.length + 1;
207
201
  if (evt.response.usage?.total_tokens) {
208
202
  yield { type: "usage", totalTokens: evt.response.usage.total_tokens };
209
203
  }
@@ -1,5 +1,5 @@
1
1
  import OpenAI from "openai";
2
- import type { Message, ToolSchema, StreamEvent, LLMProvider } from "../types.js";
2
+ import type { Message, RenderedContext, ToolSchema, StreamEvent, LLMProvider } 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 {
@@ -13,7 +13,7 @@ export declare class OpenAIChatProvider implements LLMProvider {
13
13
  maxRetries: number;
14
14
  baseDelay: number;
15
15
  }, baseURL?: string);
16
- complete(messages: Message[], tools: ToolSchema[]): Promise<Message>;
17
- stream(messages: Message[], tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
16
+ complete(context: RenderedContext, tools: ToolSchema[]): Promise<Message>;
17
+ stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
18
18
  }
19
19
  export { OpenAIChatProvider as OpenAIProvider };
@@ -16,10 +16,10 @@ export class OpenAIChatProvider {
16
16
  this.maxRetries = retry.maxRetries;
17
17
  this.baseDelay = retry.baseDelay;
18
18
  }
19
- async complete(messages, tools) {
19
+ async complete(context, tools) {
20
20
  if (this.circuit.isOpen())
21
21
  throw new Error("Circuit breaker open");
22
- const msgs = this.chat.buildMessages(messages);
22
+ const msgs = this.chat.buildMessages(context);
23
23
  let lastErr;
24
24
  for (let i = 0; i < this.maxRetries; i++) {
25
25
  try {
@@ -42,8 +42,8 @@ export class OpenAIChatProvider {
42
42
  }
43
43
  throw lastErr;
44
44
  }
45
- async *stream(messages, tools, extensions) {
46
- const msgs = this.chat.buildMessages(messages);
45
+ async *stream(context, tools, extensions) {
46
+ const msgs = this.chat.buildMessages(context);
47
47
  const toolCallBufs = {};
48
48
  const stream = await this.client.chat.completions.create({
49
49
  model: this.model,
@@ -1,5 +1,5 @@
1
1
  import OpenAI from "openai";
2
- import type { LLMProvider, Message, StreamEvent, ToolSchema } from "../types.js";
2
+ import type { LLMProvider, Message, RenderedContext, StreamEvent, ToolSchema } from "../types.js";
3
3
  import { CircuitBreaker } from "./base.js";
4
4
  import { OpenAIChatAdapter } from "./openai-chat.js";
5
5
  export declare class QwenProvider implements LLMProvider {
@@ -13,6 +13,6 @@ export declare class QwenProvider implements LLMProvider {
13
13
  maxRetries: number;
14
14
  baseDelay: number;
15
15
  }, baseURL?: string);
16
- complete(messages: Message[], tools: ToolSchema[]): Promise<Message>;
17
- stream(messages: Message[], tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
16
+ complete(context: RenderedContext, tools: ToolSchema[]): Promise<Message>;
17
+ stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
18
18
  }
@@ -18,10 +18,10 @@ export class QwenProvider {
18
18
  this.maxRetries = retry.maxRetries;
19
19
  this.baseDelay = retry.baseDelay;
20
20
  }
21
- async complete(messages, tools) {
21
+ async complete(context, tools) {
22
22
  if (this.circuit.isOpen())
23
23
  throw new Error("Circuit breaker open");
24
- const msgs = this.chat.buildMessages(messages);
24
+ const msgs = this.chat.buildMessages(context);
25
25
  let lastErr;
26
26
  for (let i = 0; i < this.maxRetries; i++) {
27
27
  try {
@@ -44,10 +44,10 @@ export class QwenProvider {
44
44
  }
45
45
  throw lastErr;
46
46
  }
47
- async *stream(messages, tools, extensions) {
47
+ async *stream(context, tools, extensions) {
48
48
  const enableThinking = Boolean(extensions?.enableThinking ?? extensions?.enable_thinking);
49
49
  const thinkingBudget = extensions?.thinkingBudget ?? extensions?.thinking_budget;
50
- const msgs = this.chat.buildMessages(messages);
50
+ const msgs = this.chat.buildMessages(context);
51
51
  const toolCallBufs = {};
52
52
  const stream = await this.client.chat.completions.create({
53
53
  model: this.model,
package/dist/types.d.ts CHANGED
@@ -117,8 +117,18 @@ export interface RetryConfig {
117
117
  * Responses `previous_response_id` without leaking those semantics into the kernel.
118
118
  */
119
119
  export type ProviderRunState = Record<string, unknown>;
120
+ /** Structured render output produced by the kernel for each LLM call. */
121
+ export interface RenderedContext {
122
+ /** Combined system text: system partition + dashboard (when non-empty).
123
+ * Anthropic → `system` param · OpenAI → messages[0] system role ·
124
+ * Gemini → `systemInstruction`. */
125
+ systemText: string;
126
+ /** Strictly alternating user / assistant / tool turns.
127
+ * Working-partition signals are already folded into the first user turn. */
128
+ turns: Message[];
129
+ }
120
130
  export interface LLMProvider {
121
131
  createRunState?(): ProviderRunState;
122
- complete(messages: Message[], tools: ToolSchema[]): Promise<Message>;
123
- stream(messages: Message[], tools: ToolSchema[], extensions?: Record<string, unknown>, state?: ProviderRunState): AsyncIterable<StreamEvent>;
132
+ complete(context: RenderedContext, tools: ToolSchema[]): Promise<Message>;
133
+ stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, state?: ProviderRunState): AsyncIterable<StreamEvent>;
124
134
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/sdk",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "DeepStrike Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@anthropic-ai/sdk": "^0.39.0",
19
- "@deepstrike/core": "0.1.10",
19
+ "@deepstrike/core": "0.1.12",
20
20
  "@google/generative-ai": "^0.24.1",
21
21
  "openai": "^4.77.0"
22
22
  },