@deepstrike/sdk 0.2.33 → 0.2.35
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/README.md +6 -0
- package/dist/providers/anthropic.js +4 -0
- package/dist/providers/openai.js +8 -1
- package/dist/runtime/runner.js +29 -25
- package/dist/types.d.ts +4 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/kongusen/deepstrike">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/kongusen/deepstrike/main/docs/public/banner.png" alt="DeepStrike" width="420" />
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
1
7
|
# DeepStrike Node.js SDK
|
|
2
8
|
|
|
3
9
|
Runtime framework built on a Rust kernel. The kernel owns loop control, context compression, governance, signal routing, and memory paging — the SDK owns all I/O (LLM calls, tool execution, disk, long-term memory).
|
|
@@ -182,6 +182,9 @@ export class AnthropicProvider {
|
|
|
182
182
|
// cache-heavy turn look tiny and suppress compaction until a 413.
|
|
183
183
|
const inputTokens = uncachedInput + cacheReadTokens + cacheCreationTokens;
|
|
184
184
|
const bySlot = estimateCacheReadBySlot(cacheReadTokens, slotBp);
|
|
185
|
+
// stop_reason is only present on message_delta (the closing frame). `max_tokens` drives
|
|
186
|
+
// the kernel's output-cap recovery; other reasons (end_turn/tool_use) are informational.
|
|
187
|
+
const stopReason = evt.delta?.stop_reason;
|
|
185
188
|
yield {
|
|
186
189
|
type: "usage",
|
|
187
190
|
totalTokens: inputTokens + outputTokens,
|
|
@@ -190,6 +193,7 @@ export class AnthropicProvider {
|
|
|
190
193
|
cacheReadInputTokens: cacheReadTokens,
|
|
191
194
|
cacheCreationInputTokens: cacheCreationTokens,
|
|
192
195
|
...(bySlot ? { cacheReadInputTokensBySlot: bySlot } : {}),
|
|
196
|
+
...(stopReason ? { stopReason } : {}),
|
|
193
197
|
};
|
|
194
198
|
}
|
|
195
199
|
}
|
package/dist/providers/openai.js
CHANGED
|
@@ -250,6 +250,11 @@ export class OpenAIChatProvider {
|
|
|
250
250
|
let inputTokens = 0;
|
|
251
251
|
let outputTokens = 0;
|
|
252
252
|
let cacheReadTokens = 0;
|
|
253
|
+
// Phase 4: OpenAI signals an output-cap truncation via finish_reason="length", which arrives on
|
|
254
|
+
// a `choices` frame separate from the trailing `usage` frame — so capture it and attach it to the
|
|
255
|
+
// usage event the runner reads. The kernel treats "length" as a truncation (== Anthropic
|
|
256
|
+
// "max_tokens"); other reasons ("stop"/"tool_calls") pass through harmlessly.
|
|
257
|
+
let finishReason;
|
|
253
258
|
for await (const chunk of stream) {
|
|
254
259
|
if (chunk.usage) {
|
|
255
260
|
totalTokens = chunk.usage.total_tokens;
|
|
@@ -261,6 +266,8 @@ export class OpenAIChatProvider {
|
|
|
261
266
|
const choice = chunk.choices[0];
|
|
262
267
|
if (!choice)
|
|
263
268
|
continue;
|
|
269
|
+
if (choice.finish_reason)
|
|
270
|
+
finishReason = choice.finish_reason;
|
|
264
271
|
const delta = choice.delta;
|
|
265
272
|
if (!delta)
|
|
266
273
|
continue;
|
|
@@ -317,7 +324,7 @@ export class OpenAIChatProvider {
|
|
|
317
324
|
rememberStream();
|
|
318
325
|
yield* emitPendingToolCalls();
|
|
319
326
|
if (totalTokens > 0)
|
|
320
|
-
yield { type: "usage", totalTokens, inputTokens, outputTokens, ...(cacheReadTokens > 0 ? { cacheReadInputTokens: cacheReadTokens } : {}) };
|
|
327
|
+
yield { type: "usage", totalTokens, inputTokens, outputTokens, ...(cacheReadTokens > 0 ? { cacheReadInputTokens: cacheReadTokens } : {}), ...(finishReason ? { stopReason: finishReason } : {}) };
|
|
321
328
|
}
|
|
322
329
|
/**
|
|
323
330
|
* Default `prompt_cache_key` derived from the cacheable prefix (system prompt +
|
package/dist/runtime/runner.js
CHANGED
|
@@ -5,7 +5,7 @@ import { peekProviderReplay, seedProviderReplayFromEvents } from "./provider-rep
|
|
|
5
5
|
import { sanitizeReplayText } from "./replay-sanitize.js";
|
|
6
6
|
import { buildLlmCompletedEvent, buildRunTerminalEvent, buildWorkflowNodeCompletedEvent, buildWorkflowNodesSubmittedEvent, recoverCompletedWorkflowNodes, recoverSubmittedWorkflowNodes, repairEventsForRecovery, } from "./session-repair.js";
|
|
7
7
|
import { KernelPrimitivesDashboard } from "./kernel-primitives-dashboard.js";
|
|
8
|
-
import { capabilityMarker, capabilitySkill, capabilityTool, capabilityCommandMount, capabilityCommandUnmount, kernelAction, kernelApply, kernelMaybeAction,
|
|
8
|
+
import { capabilityMarker, capabilitySkill, capabilityTool, capabilityCommandMount, capabilityCommandUnmount, kernelAction, kernelApply, kernelMaybeAction, messageToKernelMessage, skillMetadataToKernel, taskUpdateToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
|
|
9
9
|
import { agentRunSpecToKernel, findSpawnProcessObservation, milestoneCheckPass, milestoneCheckResultToKernel, spawnObservationToManifest, subAgentResultToKernel, submitWorkflowNodesToKernel, submitWorkflowToKernel, workflowBudgetNote, workflowNodeToManifest, workflowNodeToSpec, workflowSpecToKernel, } from "../types/agent.js";
|
|
10
10
|
import { defaultSubAgentOrchestrator } from "./sub-agent-orchestrator.js";
|
|
11
11
|
import { extractJsonValue, schemaInstruction, schemaRetryInstruction, validateAgainstSchema, } from "./output-schema.js";
|
|
@@ -1077,7 +1077,6 @@ export class RuntimeRunner {
|
|
|
1077
1077
|
let action = resumeMidRun
|
|
1078
1078
|
? kernelAction(runtime, this.pendingObservations, { kind: "resume" })
|
|
1079
1079
|
: kernelAction(runtime, this.pendingObservations, startPayload);
|
|
1080
|
-
let hasAttemptedReactiveCompact = false;
|
|
1081
1080
|
// P0-C: the skill loaded and in effect going into the current turn (updated when the model's
|
|
1082
1081
|
// `skill` tool call resolves). Drives the per-turn `activeSkill` metric → dwell measurement.
|
|
1083
1082
|
let activeSkill;
|
|
@@ -1158,7 +1157,7 @@ export class RuntimeRunner {
|
|
|
1158
1157
|
let turnCacheReadTokens = 0;
|
|
1159
1158
|
let turnCacheCreationTokens = 0;
|
|
1160
1159
|
let turnCacheReadBySlot;
|
|
1161
|
-
let
|
|
1160
|
+
let turnStopReason;
|
|
1162
1161
|
const abortSignal = this.abortController?.signal;
|
|
1163
1162
|
try {
|
|
1164
1163
|
for await (const evt of this.opts.provider.stream(context, tools, Object.keys(ext).length ? ext : undefined, providerState, abortSignal)) {
|
|
@@ -1178,6 +1177,10 @@ export class RuntimeRunner {
|
|
|
1178
1177
|
// I1: per-slot attribution forwarded into TurnMetrics. Undefined when the provider
|
|
1179
1178
|
// doesn't honor cache_control (OpenAI-family auto-cache).
|
|
1180
1179
|
turnCacheReadBySlot = usageEvt.cacheReadInputTokensBySlot;
|
|
1180
|
+
// Phase 4: stop_reason drives the kernel's max-output-tokens recovery. The closing
|
|
1181
|
+
// usage frame carries it; keep the last non-empty value seen this turn.
|
|
1182
|
+
if (usageEvt.stopReason)
|
|
1183
|
+
turnStopReason = usageEvt.stopReason;
|
|
1181
1184
|
continue;
|
|
1182
1185
|
}
|
|
1183
1186
|
yield evt;
|
|
@@ -1190,24 +1193,32 @@ export class RuntimeRunner {
|
|
|
1190
1193
|
}
|
|
1191
1194
|
}
|
|
1192
1195
|
catch (err) {
|
|
1193
|
-
// #2-B-ii: an aborted in-flight request surfaces as an AbortError — treat it as an interrupt
|
|
1194
|
-
// (the loop-top `interrupted` check converts it to a clean `timeout`/UserAbort), not a crash.
|
|
1195
1196
|
if (abortSignal?.aborted) {
|
|
1197
|
+
// #2-B-ii: an aborted in-flight request surfaces as an AbortError — treat it as an
|
|
1198
|
+
// interrupt (the post-stream `aborted` check below converts it to a clean
|
|
1199
|
+
// timeout/UserAbort), not a crash or a provider error.
|
|
1196
1200
|
this.interrupted = true;
|
|
1197
1201
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1202
|
+
else {
|
|
1203
|
+
// Reactive recovery is now a kernel decision. Forward the raw provider error and
|
|
1204
|
+
// dispatch whatever the kernel returns: `call_provider` to retry with a freshly
|
|
1205
|
+
// compacted context, or `done` to terminate with an honest `ContextOverflow`. The
|
|
1206
|
+
// classify + compact + retry + give-up policy lives in the kernel (one place), not
|
|
1207
|
+
// duplicated across the four SDK runners. `continue` re-enters the loop: a recovered
|
|
1208
|
+
// turn persists its compaction archive via the loop-top appendObservations, and a
|
|
1209
|
+
// terminal `done` exits through `isTerminal()` into the run_terminal emit below.
|
|
1210
|
+
action = kernelAction(runtime, this.pendingObservations, {
|
|
1211
|
+
kind: "provider_error",
|
|
1212
|
+
message: formatToolError(err),
|
|
1213
|
+
});
|
|
1214
|
+
// Withholding (query.ts parity): surface the raw provider error only when the kernel
|
|
1215
|
+
// could NOT recover (it returned a terminal). On a recovered retry (`call_provider`)
|
|
1216
|
+
// the error stays hidden, so embedders that terminate on `error` events don't see a
|
|
1217
|
+
// phantom failure mid-recovery.
|
|
1218
|
+
if (action.kind === "done") {
|
|
1219
|
+
yield { type: "error", message: formatToolError(err) };
|
|
1205
1220
|
}
|
|
1206
|
-
|
|
1207
|
-
if (!shouldRetry) {
|
|
1208
|
-
yield { type: "error", message: formatToolError(err) };
|
|
1209
|
-
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
1210
|
-
break;
|
|
1221
|
+
continue;
|
|
1211
1222
|
}
|
|
1212
1223
|
}
|
|
1213
1224
|
// #2-B-ii: stream aborted (preempt/interrupt) via the break path (provider yielded no error) —
|
|
@@ -1217,14 +1228,6 @@ export class RuntimeRunner {
|
|
|
1217
1228
|
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
1218
1229
|
break;
|
|
1219
1230
|
}
|
|
1220
|
-
if (shouldRetry) {
|
|
1221
|
-
action = {
|
|
1222
|
-
kind: "call_provider",
|
|
1223
|
-
context: runtime.render(),
|
|
1224
|
-
tools,
|
|
1225
|
-
};
|
|
1226
|
-
continue;
|
|
1227
|
-
}
|
|
1228
1231
|
const assistantMessage = {
|
|
1229
1232
|
role: "assistant",
|
|
1230
1233
|
content: finalText,
|
|
@@ -1237,6 +1240,7 @@ export class RuntimeRunner {
|
|
|
1237
1240
|
...(turnInputTokens > 0 ? { observed_input_tokens: turnInputTokens } : {}),
|
|
1238
1241
|
...(turnOutputTokens > 0 ? { observed_output_tokens: turnOutputTokens } : {}),
|
|
1239
1242
|
now_ms: Date.now(),
|
|
1243
|
+
...(turnStopReason ? { stop_reason: turnStopReason } : {}),
|
|
1240
1244
|
};
|
|
1241
1245
|
let nextAction = kernelMaybeAction(runtime, this.pendingObservations, providerEvent);
|
|
1242
1246
|
if (!nextAction && this.pendingObservations.some(o => o.kind === "suspended")) {
|
package/dist/types.d.ts
CHANGED
|
@@ -93,6 +93,10 @@ export interface UsageEvent extends StreamEvent {
|
|
|
93
93
|
tools?: number;
|
|
94
94
|
messages?: number;
|
|
95
95
|
};
|
|
96
|
+
/** Provider stop reason for the response — `max_tokens` (Anthropic) / `length` (OpenAI) flag an
|
|
97
|
+
* output-cap truncation, which drives the kernel's max-output-tokens recovery. Absent when the
|
|
98
|
+
* provider doesn't report one. */
|
|
99
|
+
stopReason?: string;
|
|
96
100
|
}
|
|
97
101
|
export type ToolChunk = string | {
|
|
98
102
|
type: "text";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepstrike/sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.35",
|
|
4
4
|
"description": "DeepStrike Node.js SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"@anthropic-ai/sdk": "^0.99.0",
|
|
75
|
-
"@deepstrike/core": "0.2.
|
|
75
|
+
"@deepstrike/core": "0.2.35",
|
|
76
76
|
"@google/generative-ai": "^0.24.1",
|
|
77
77
|
"openai": "^5.23.2"
|
|
78
78
|
},
|