@deepstrike/sdk 0.2.11 → 0.2.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.
@@ -35,18 +35,36 @@ export const endpointProfiles = {
35
35
  protocol: "openai-chat",
36
36
  baseURL: "https://api.minimaxi.com/v1",
37
37
  },
38
+ "deepseek.anthropic": {
39
+ id: "deepseek.anthropic",
40
+ providerId: "deepseek",
41
+ protocol: "anthropic-messages",
42
+ baseURL: "https://api.deepseek.com/anthropic",
43
+ },
38
44
  "deepseek.openai": {
39
45
  id: "deepseek.openai",
40
46
  providerId: "deepseek",
41
47
  protocol: "openai-chat",
42
48
  baseURL: "https://api.deepseek.com",
43
49
  },
50
+ "kimi.anthropic": {
51
+ id: "kimi.anthropic",
52
+ providerId: "kimi",
53
+ protocol: "anthropic-messages",
54
+ baseURL: "https://api.moonshot.ai/anthropic",
55
+ },
44
56
  "kimi.openai": {
45
57
  id: "kimi.openai",
46
58
  providerId: "kimi",
47
59
  protocol: "openai-chat",
48
60
  baseURL: "https://api.moonshot.cn/v1",
49
61
  },
62
+ "qwen.anthropic": {
63
+ id: "qwen.anthropic",
64
+ providerId: "qwen",
65
+ protocol: "anthropic-messages",
66
+ baseURL: "https://dashscope-intl.aliyuncs.com/apps/anthropic",
67
+ },
50
68
  "qwen.dashscope": {
51
69
  id: "qwen.dashscope",
52
70
  providerId: "qwen",
@@ -77,6 +95,12 @@ export const endpointProfiles = {
77
95
  protocol: "gemini-embeddings",
78
96
  baseURL: "https://generativelanguage.googleapis.com",
79
97
  },
98
+ "glm.anthropic": {
99
+ id: "glm.anthropic",
100
+ providerId: "glm",
101
+ protocol: "anthropic-messages",
102
+ baseURL: "https://api.z.ai/api/anthropic",
103
+ },
80
104
  "glm.openai": {
81
105
  id: "glm.openai",
82
106
  providerId: "glm",
@@ -375,28 +399,28 @@ export const modelProfiles = {
375
399
  },
376
400
  // ── DeepSeek ───────────────────────────────────────────────────────────────
377
401
  "deepseek/deepseek-chat": {
378
- id: "deepseek/deepseek-chat", providerId: "deepseek", defaultEndpointId: "deepseek.openai",
402
+ id: "deepseek/deepseek-chat", providerId: "deepseek", defaultEndpointId: "deepseek.anthropic",
379
403
  contextWindow: 64_000,
380
404
  modalities: { input: ["text"], output: ["text"] },
381
405
  tools: { supported: true }, reasoning: { supported: false, preserveAcrossToolTurns: false },
382
406
  policy: { maxTurns: 25 },
383
407
  },
384
408
  "deepseek/deepseek-reasoner": {
385
- id: "deepseek/deepseek-reasoner", providerId: "deepseek", defaultEndpointId: "deepseek.openai",
409
+ id: "deepseek/deepseek-reasoner", providerId: "deepseek", defaultEndpointId: "deepseek.anthropic",
386
410
  contextWindow: 64_000,
387
411
  modalities: { input: ["text"], output: ["text"] },
388
412
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: true },
389
413
  policy: { maxTurns: 50 },
390
414
  },
391
415
  "deepseek/deepseek-v4-flash": {
392
- id: "deepseek/deepseek-v4-flash", providerId: "deepseek", defaultEndpointId: "deepseek.openai",
416
+ id: "deepseek/deepseek-v4-flash", providerId: "deepseek", defaultEndpointId: "deepseek.anthropic",
393
417
  contextWindow: 1_000_000,
394
418
  modalities: { input: ["text"], output: ["text"] },
395
419
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: true },
396
420
  policy: { maxTurns: 20 },
397
421
  },
398
422
  "deepseek/deepseek-v4-pro": {
399
- id: "deepseek/deepseek-v4-pro", providerId: "deepseek", defaultEndpointId: "deepseek.openai",
423
+ id: "deepseek/deepseek-v4-pro", providerId: "deepseek", defaultEndpointId: "deepseek.anthropic",
400
424
  contextWindow: 1_000_000,
401
425
  modalities: { input: ["text"], output: ["text"] },
402
426
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: true },
@@ -404,48 +428,48 @@ export const modelProfiles = {
404
428
  },
405
429
  // ── Kimi ───────────────────────────────────────────────────────────────────
406
430
  "kimi/moonshot-v1-8k": {
407
- id: "kimi/moonshot-v1-8k", providerId: "kimi", defaultEndpointId: "kimi.openai",
431
+ id: "kimi/moonshot-v1-8k", providerId: "kimi", defaultEndpointId: "kimi.anthropic",
408
432
  contextWindow: 8_000,
409
433
  modalities: { input: ["text"], output: ["text"] },
410
434
  tools: { supported: true }, reasoning: { supported: false, preserveAcrossToolTurns: false },
411
435
  policy: { maxTurns: 15 },
412
436
  },
413
437
  "kimi/moonshot-v1-32k": {
414
- id: "kimi/moonshot-v1-32k", providerId: "kimi", defaultEndpointId: "kimi.openai",
438
+ id: "kimi/moonshot-v1-32k", providerId: "kimi", defaultEndpointId: "kimi.anthropic",
415
439
  contextWindow: 32_000,
416
440
  modalities: { input: ["text"], output: ["text"] },
417
441
  tools: { supported: true }, reasoning: { supported: false, preserveAcrossToolTurns: false },
418
442
  policy: { maxTurns: 20 },
419
443
  },
420
444
  "kimi/moonshot-v1-128k": {
421
- id: "kimi/moonshot-v1-128k", providerId: "kimi", defaultEndpointId: "kimi.openai",
445
+ id: "kimi/moonshot-v1-128k", providerId: "kimi", defaultEndpointId: "kimi.anthropic",
422
446
  contextWindow: 128_000,
423
447
  modalities: { input: ["text", "image"], output: ["text"] },
424
448
  tools: { supported: true }, reasoning: { supported: false, preserveAcrossToolTurns: false },
425
449
  policy: { maxTurns: 30 },
426
450
  },
427
451
  "kimi/kimi-k2.5": {
428
- id: "kimi/kimi-k2.5", providerId: "kimi", defaultEndpointId: "kimi.openai",
452
+ id: "kimi/kimi-k2.5", providerId: "kimi", defaultEndpointId: "kimi.anthropic",
429
453
  contextWindow: 256_000,
430
454
  modalities: { input: ["text", "image"], output: ["text"] },
431
455
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
432
456
  policy: { maxTurns: 30 },
433
457
  },
434
458
  "kimi/kimi-k2.6": {
435
- id: "kimi/kimi-k2.6", providerId: "kimi", defaultEndpointId: "kimi.openai",
459
+ id: "kimi/kimi-k2.6", providerId: "kimi", defaultEndpointId: "kimi.anthropic",
436
460
  modalities: { input: ["text"], output: ["text"] },
437
461
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
438
462
  policy: { maxTurns: 35 },
439
463
  },
440
464
  "kimi/kimi-k2-thinking": {
441
- id: "kimi/kimi-k2-thinking", providerId: "kimi", defaultEndpointId: "kimi.openai",
465
+ id: "kimi/kimi-k2-thinking", providerId: "kimi", defaultEndpointId: "kimi.anthropic",
442
466
  contextWindow: 256_000,
443
467
  modalities: { input: ["text"], output: ["text"] },
444
468
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: true },
445
469
  policy: { maxTurns: 50 },
446
470
  },
447
471
  "kimi/kimi-k2-thinking-turbo": {
448
- id: "kimi/kimi-k2-thinking-turbo", providerId: "kimi", defaultEndpointId: "kimi.openai",
472
+ id: "kimi/kimi-k2-thinking-turbo", providerId: "kimi", defaultEndpointId: "kimi.anthropic",
449
473
  contextWindow: 256_000,
450
474
  modalities: { input: ["text"], output: ["text"] },
451
475
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: true },
@@ -453,91 +477,91 @@ export const modelProfiles = {
453
477
  },
454
478
  // ── Qwen ───────────────────────────────────────────────────────────────────
455
479
  "qwen/qwen3.7-max-preview": {
456
- id: "qwen/qwen3.7-max-preview", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
480
+ id: "qwen/qwen3.7-max-preview", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
457
481
  contextWindow: 256_000,
458
482
  modalities: { input: ["text"], output: ["text"] },
459
483
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
460
484
  policy: { maxTurns: 45 },
461
485
  },
462
486
  "qwen/qwen3.7-plus-preview": {
463
- id: "qwen/qwen3.7-plus-preview", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
487
+ id: "qwen/qwen3.7-plus-preview", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
464
488
  contextWindow: 1_000_000,
465
489
  modalities: { input: ["text", "image"], output: ["text"] },
466
490
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
467
491
  policy: { maxTurns: 40 },
468
492
  },
469
493
  "qwen/qwen3.6-max-preview": {
470
- id: "qwen/qwen3.6-max-preview", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
494
+ id: "qwen/qwen3.6-max-preview", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
471
495
  contextWindow: 256_000,
472
496
  modalities: { input: ["text"], output: ["text"] },
473
497
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
474
498
  policy: { maxTurns: 40 },
475
499
  },
476
500
  "qwen/qwen3.6-plus": {
477
- id: "qwen/qwen3.6-plus", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
501
+ id: "qwen/qwen3.6-plus", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
478
502
  contextWindow: 1_000_000,
479
503
  modalities: { input: ["text", "image"], output: ["text"] },
480
504
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
481
505
  policy: { maxTurns: 35 },
482
506
  },
483
507
  "qwen/qwen3.6-flash": {
484
- id: "qwen/qwen3.6-flash", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
508
+ id: "qwen/qwen3.6-flash", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
485
509
  contextWindow: 1_000_000,
486
510
  modalities: { input: ["text", "image"], output: ["text"] },
487
511
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
488
512
  policy: { maxTurns: 20 },
489
513
  },
490
514
  "qwen/qwen3.6-35b-a3b": {
491
- id: "qwen/qwen3.6-35b-a3b", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
515
+ id: "qwen/qwen3.6-35b-a3b", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
492
516
  contextWindow: 256_000,
493
517
  modalities: { input: ["text", "image"], output: ["text"] },
494
518
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
495
519
  policy: { maxTurns: 25 },
496
520
  },
497
521
  "qwen/qwen3.6-27b": {
498
- id: "qwen/qwen3.6-27b", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
522
+ id: "qwen/qwen3.6-27b", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
499
523
  contextWindow: 256_000,
500
524
  modalities: { input: ["text", "image"], output: ["text"] },
501
525
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
502
526
  policy: { maxTurns: 25 },
503
527
  },
504
528
  "qwen/qwen3.5-plus": {
505
- id: "qwen/qwen3.5-plus", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
529
+ id: "qwen/qwen3.5-plus", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
506
530
  contextWindow: 1_000_000,
507
531
  modalities: { input: ["text", "image"], output: ["text"] },
508
532
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
509
533
  policy: { maxTurns: 35 },
510
534
  },
511
535
  "qwen/qwen3.5-flash": {
512
- id: "qwen/qwen3.5-flash", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
536
+ id: "qwen/qwen3.5-flash", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
513
537
  contextWindow: 1_000_000,
514
538
  modalities: { input: ["text", "image"], output: ["text"] },
515
539
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
516
540
  policy: { maxTurns: 20 },
517
541
  },
518
542
  "qwen/qwen3.5-397b-a17b": {
519
- id: "qwen/qwen3.5-397b-a17b", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
543
+ id: "qwen/qwen3.5-397b-a17b", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
520
544
  contextWindow: 256_000,
521
545
  modalities: { input: ["text", "image"], output: ["text"] },
522
546
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
523
547
  policy: { maxTurns: 35 },
524
548
  },
525
549
  "qwen/qwen3.5-122b-a10b": {
526
- id: "qwen/qwen3.5-122b-a10b", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
550
+ id: "qwen/qwen3.5-122b-a10b", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
527
551
  contextWindow: 256_000,
528
552
  modalities: { input: ["text", "image"], output: ["text"] },
529
553
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
530
554
  policy: { maxTurns: 25 },
531
555
  },
532
556
  "qwen/qwen3.5-35b-a3b": {
533
- id: "qwen/qwen3.5-35b-a3b", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
557
+ id: "qwen/qwen3.5-35b-a3b", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
534
558
  contextWindow: 256_000,
535
559
  modalities: { input: ["text", "image"], output: ["text"] },
536
560
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
537
561
  policy: { maxTurns: 20 },
538
562
  },
539
563
  "qwen/qwen3.5-27b": {
540
- id: "qwen/qwen3.5-27b", providerId: "qwen", defaultEndpointId: "qwen.dashscope",
564
+ id: "qwen/qwen3.5-27b", providerId: "qwen", defaultEndpointId: "qwen.anthropic",
541
565
  contextWindow: 256_000,
542
566
  modalities: { input: ["text", "image"], output: ["text"] },
543
567
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: false },
@@ -645,28 +669,28 @@ export const modelProfiles = {
645
669
  },
646
670
  // ── GLM ────────────────────────────────────────────────────────────────────
647
671
  "glm/glm-5.1": {
648
- id: "glm/glm-5.1", providerId: "glm", defaultEndpointId: "glm.openai",
672
+ id: "glm/glm-5.1", providerId: "glm", defaultEndpointId: "glm.anthropic",
649
673
  contextWindow: 200_000,
650
674
  modalities: { input: ["text"], output: ["text"] },
651
675
  tools: { supported: true }, reasoning: { supported: true, preserveAcrossToolTurns: true },
652
676
  policy: { maxTurns: 50 },
653
677
  },
654
678
  "glm/glm-4-plus": {
655
- id: "glm/glm-4-plus", providerId: "glm", defaultEndpointId: "glm.openai",
679
+ id: "glm/glm-4-plus", providerId: "glm", defaultEndpointId: "glm.anthropic",
656
680
  contextWindow: 128_000,
657
681
  modalities: { input: ["text", "image"], output: ["text"] },
658
682
  tools: { supported: true }, reasoning: { supported: false, preserveAcrossToolTurns: false },
659
683
  policy: { maxTurns: 35 },
660
684
  },
661
685
  "glm/glm-4-flash": {
662
- id: "glm/glm-4-flash", providerId: "glm", defaultEndpointId: "glm.openai",
686
+ id: "glm/glm-4-flash", providerId: "glm", defaultEndpointId: "glm.anthropic",
663
687
  contextWindow: 128_000,
664
688
  modalities: { input: ["text"], output: ["text"] },
665
689
  tools: { supported: true }, reasoning: { supported: false, preserveAcrossToolTurns: false },
666
690
  policy: { maxTurns: 15 },
667
691
  },
668
692
  "glm/glm-4-air": {
669
- id: "glm/glm-4-air", providerId: "glm", defaultEndpointId: "glm.openai",
693
+ id: "glm/glm-4-air", providerId: "glm", defaultEndpointId: "glm.anthropic",
670
694
  contextWindow: 128_000,
671
695
  modalities: { input: ["text"], output: ["text"] },
672
696
  tools: { supported: true }, reasoning: { supported: false, preserveAcrossToolTurns: false },
@@ -1,7 +1,19 @@
1
1
  import OpenAI from "openai";
2
2
  import type { LLMProvider, Message, ProviderDescriptor, RenderedContext, StreamEvent, ToolSchema, RuntimePolicy, ProviderReplay } from "../types.js";
3
+ import { AnthropicProvider } from "./anthropic.js";
3
4
  import { CircuitBreaker } from "./base.js";
4
5
  import { OpenAIChatAdapter } from "./openai-chat.js";
6
+ /**
7
+ * Qwen over its Anthropic-compatible endpoint.
8
+ */
9
+ export declare class QwenAnthropicProvider extends AnthropicProvider {
10
+ constructor(apiKey: string, model?: string, retry?: {
11
+ maxRetries: number;
12
+ baseDelay: number;
13
+ }, baseURL?: string);
14
+ protected providerName(): string;
15
+ runtimePolicy(): RuntimePolicy;
16
+ }
5
17
  export declare class QwenProvider implements LLMProvider {
6
18
  protected readonly model: string;
7
19
  protected client: OpenAI;
@@ -1,9 +1,9 @@
1
1
  import OpenAI from "openai";
2
2
  import { withServerRuntimeGuard } from "../runtime/server.js";
3
- import { CircuitBreaker, omitExtensionKeys } from "./base.js";
3
+ import { AnthropicProvider } from "./anthropic.js";
4
+ import { CircuitBreaker, omitExtensionKeys, openAICachedPromptTokens } from "./base.js";
4
5
  import { OpenAIChatAdapter } from "./openai-chat.js";
5
6
  import { endpointProfiles } from "./profiles.js";
6
- const QWEN_BASE = endpointProfiles["qwen.dashscope"].baseURL;
7
7
  const QWEN_POLICIES = {
8
8
  "qwen3.7-max-preview": { maxTurns: 45 },
9
9
  "qwen3.7-plus-preview": { maxTurns: 40 },
@@ -19,6 +19,23 @@ const QWEN_POLICIES = {
19
19
  "qwen3.5-35b-a3b": { maxTurns: 20 },
20
20
  "qwen3.5-27b": { maxTurns: 20 },
21
21
  };
22
+ /**
23
+ * Qwen over its Anthropic-compatible endpoint.
24
+ */
25
+ export class QwenAnthropicProvider extends AnthropicProvider {
26
+ constructor(apiKey, model = "qwen3.6-plus", retry, baseURL = endpointProfiles["qwen.anthropic"].baseURL) {
27
+ super(apiKey, model, retry, {
28
+ baseURL,
29
+ authMode: "api-key",
30
+ });
31
+ }
32
+ providerName() {
33
+ return "qwen";
34
+ }
35
+ runtimePolicy() {
36
+ return QWEN_POLICIES[this.model] ?? {};
37
+ }
38
+ }
22
39
  export class QwenProvider {
23
40
  model;
24
41
  client;
@@ -26,7 +43,7 @@ export class QwenProvider {
26
43
  maxRetries;
27
44
  baseDelay;
28
45
  chat = new OpenAIChatAdapter();
29
- constructor(apiKey, model = "qwen3.6-plus", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = QWEN_BASE) {
46
+ constructor(apiKey, model = "qwen3.6-plus", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = endpointProfiles["qwen.dashscope"].baseURL) {
30
47
  this.model = model;
31
48
  this.client = withServerRuntimeGuard(() => new OpenAI({ apiKey, baseURL }));
32
49
  this.circuit = new CircuitBreaker();
@@ -113,11 +130,13 @@ export class QwenProvider {
113
130
  let totalTokens = 0;
114
131
  let inputTokens = 0;
115
132
  let outputTokens = 0;
133
+ let cacheReadTokens = 0;
116
134
  for await (const chunk of stream) {
117
135
  if (chunk.usage) {
118
136
  totalTokens = chunk.usage.total_tokens;
119
137
  inputTokens = chunk.usage.prompt_tokens ?? 0;
120
138
  outputTokens = chunk.usage.completion_tokens ?? 0;
139
+ cacheReadTokens = openAICachedPromptTokens(chunk.usage);
121
140
  continue;
122
141
  }
123
142
  const choice = chunk.choices[0];
@@ -184,7 +203,7 @@ export class QwenProvider {
184
203
  yield { type: "tool_call", id: tb.id, name: tb.name, arguments: args };
185
204
  }
186
205
  if (totalTokens > 0)
187
- yield { type: "usage", totalTokens, inputTokens, outputTokens };
206
+ yield { type: "usage", totalTokens, inputTokens, outputTokens, ...(cacheReadTokens > 0 ? { cacheReadInputTokens: cacheReadTokens } : {}) };
188
207
  }
189
208
  thinkingExtraBody(extensions) {
190
209
  const enableThinking = Boolean(extensions?.enableThinking ?? extensions?.enable_thinking);
@@ -1,4 +1,4 @@
1
- import type { LLMProvider, Message, ToolSchema, StreamEvent, ToolSuspendEvent, PermissionRequestEvent, PermissionResponse, AsyncSummarizer, DreamSummarizer } from "../types.js";
1
+ import type { LLMProvider, Message, ContentPart, ToolSchema, StreamEvent, ToolSuspendEvent, PermissionRequestEvent, PermissionResponse, AsyncSummarizer, DreamSummarizer } from "../types.js";
2
2
  import type { DreamStore, MemoryEntry, MemoryQuery, MemoryWriteRequest } from "../memory/protocols.js";
3
3
  import type { KnowledgeSource } from "../knowledge/source.js";
4
4
  import type { SignalSource } from "../signals/types.js";
@@ -206,6 +206,8 @@ export declare class RuntimeRunner {
206
206
  sessionId: string;
207
207
  goal: string;
208
208
  criteria?: string[];
209
+ /** Multimodal inputs (images / audio) attached to the task as a user message. */
210
+ attachments?: ContentPart[];
209
211
  extensions?: Record<string, unknown>;
210
212
  /** Parent transcript to preload (e.g. sub-agent full context inheritance). */
211
213
  inheritEvents?: Array<{
@@ -458,9 +458,10 @@ export class RuntimeRunner {
458
458
  criteria: req.criteria ?? [],
459
459
  agent_id: this.opts.agentId,
460
460
  system_prompt: this.opts.systemPrompt,
461
+ ...(req.attachments?.length ? { attachments: req.attachments } : {}),
461
462
  });
462
463
  }
463
- yield* this.execute(req.sessionId, req.goal, req.criteria ?? [], req.extensions, prior.length > 0 ? prior : undefined, midRun);
464
+ yield* this.execute(req.sessionId, req.goal, req.criteria ?? [], req.extensions, prior.length > 0 ? prior : undefined, midRun, req.attachments);
464
465
  }
465
466
  async *wake(sessionId, extensions) {
466
467
  const events = await this.opts.sessionLog.read(sessionId);
@@ -470,7 +471,7 @@ export class RuntimeRunner {
470
471
  if (!startEntry)
471
472
  throw new Error(`No run_started event for session: ${sessionId}`);
472
473
  const start = startEntry.event;
473
- yield* this.execute(sessionId, start.goal, start.criteria, extensions, events, true);
474
+ yield* this.execute(sessionId, start.goal, start.criteria, extensions, events, true, start.attachments);
474
475
  }
475
476
  async *dream(agentId, nowMs = Date.now()) {
476
477
  if (!this.opts.dreamStore)
@@ -623,7 +624,7 @@ export class RuntimeRunner {
623
624
  }
624
625
  return { approved, denied, events };
625
626
  }
626
- async *execute(sessionId, goal, criteria, extensions, priorEvents, resumeMidRun = false) {
627
+ async *execute(sessionId, goal, criteria, extensions, priorEvents, resumeMidRun = false, attachments) {
627
628
  this.interrupted = false;
628
629
  this.pendingObservations = [];
629
630
  this.pendingSpoolOutputs.clear();
@@ -791,6 +792,16 @@ export class RuntimeRunner {
791
792
  },
792
793
  });
793
794
  }
795
+ // Multimodal upload: seed the user's attachments (images/audio) as a history
796
+ // message before start_run pushes the "[TASK STATE]" anchor. init_task does not
797
+ // clear history, so order becomes [attachment user msg, "Proceed…"] — both land
798
+ // in the first render. On resume the message is already in the replayed history.
799
+ if (!resumeMidRun && attachments?.length) {
800
+ kernelApply(runtime, this.pendingObservations, {
801
+ kind: "add_history_message",
802
+ message: attachmentsToKernelMessage(attachments),
803
+ });
804
+ }
794
805
  let action = resumeMidRun
795
806
  ? kernelAction(runtime, this.pendingObservations, { kind: "resume" })
796
807
  : kernelAction(runtime, this.pendingObservations, startPayload);
@@ -1227,6 +1238,31 @@ export class RuntimeRunner {
1227
1238
  function isMidRun(events) {
1228
1239
  return events.length > 0 && !events.some(e => e.event.kind === "run_terminal");
1229
1240
  }
1241
+ /**
1242
+ * Build a kernel `add_history_message` payload from user attachments: a `user`
1243
+ * message whose content is the multimodal parts in the kernel's serde shape
1244
+ * (`Content::Parts`; image `media_type`, not `mediaType`). Lets a caller upload
1245
+ * images/audio with the task — the message lands in history before the first render.
1246
+ */
1247
+ function attachmentsToKernelMessage(parts) {
1248
+ const content = parts.map(p => {
1249
+ if (p.type === "image") {
1250
+ return {
1251
+ type: "image",
1252
+ ...(p.url ? { url: p.url } : {}),
1253
+ ...(p.data ? { data: p.data } : {}),
1254
+ ...(p.mediaType ? { media_type: p.mediaType } : {}),
1255
+ ...(p.detail ? { detail: p.detail } : {}),
1256
+ };
1257
+ }
1258
+ if (p.type === "audio")
1259
+ return { type: "audio", data: p.data, media_type: p.mediaType };
1260
+ if (p.type === "text")
1261
+ return { type: "text", text: p.text };
1262
+ return { type: "text", text: "" };
1263
+ });
1264
+ return { role: "user", content };
1265
+ }
1230
1266
  function compressionAction(action) {
1231
1267
  if (action === "snip_compact" ||
1232
1268
  action === "micro_compact" ||
@@ -1,4 +1,4 @@
1
- import type { ProviderReplay, ToolCall, ToolErrorKind } from "../types.js";
1
+ import type { ContentPart, ProviderReplay, ToolCall, ToolErrorKind } from "../types.js";
2
2
  import type { KernelEventCategory, KernelPrimitive } from "./kernel-event-log.js";
3
3
  export type RollbackReason = {
4
4
  kind: "fatal_tool_error";
@@ -26,6 +26,7 @@ export type SessionEvent = {
26
26
  criteria: string[];
27
27
  agent_id?: string;
28
28
  system_prompt?: string;
29
+ attachments?: ContentPart[];
29
30
  } | {
30
31
  kind: "llm_completed";
31
32
  turn: number;
package/dist/types.d.ts CHANGED
@@ -73,6 +73,18 @@ export interface ToolCallEvent extends StreamEvent {
73
73
  name: string;
74
74
  arguments: Record<string, unknown>;
75
75
  }
76
+ export interface UsageEvent extends StreamEvent {
77
+ type: "usage";
78
+ /** Full prompt size + output (the authoritative prompt size for context accounting). */
79
+ totalTokens: number;
80
+ /** Full prompt size: uncached input + cache reads + cache writes. */
81
+ inputTokens?: number;
82
+ outputTokens?: number;
83
+ /** Prompt tokens served from cache this request (billed ~0.1x). Subset of inputTokens. */
84
+ cacheReadInputTokens?: number;
85
+ /** Prompt tokens written to cache this request (billed ~1.25x). Subset of inputTokens. */
86
+ cacheCreationInputTokens?: number;
87
+ }
76
88
  export type ToolChunk = string | {
77
89
  type: "text";
78
90
  text: string;
@@ -169,9 +181,14 @@ export interface ToolDeniedEvent extends StreamEvent {
169
181
  reason: string;
170
182
  }
171
183
  export interface TokenUsage {
184
+ /** Full prompt size: uncached input + cache reads + cache writes. */
172
185
  inputTokens: number;
173
186
  outputTokens: number;
174
187
  totalTokens: number;
188
+ /** Prompt tokens served from cache (billed ~0.1x). Subset of inputTokens. */
189
+ cacheReadInputTokens?: number;
190
+ /** Prompt tokens written to cache (billed ~1.25x). Subset of inputTokens. */
191
+ cacheCreationInputTokens?: number;
175
192
  }
176
193
  export interface ProviderToolSpec {
177
194
  name: string;
@@ -236,8 +253,24 @@ export interface RenderedContext {
236
253
  systemStable?: string;
237
254
  /** Knowledge (memory retrievals, skill definitions, artifacts). Anthropic system[1] with cache_control. */
238
255
  systemKnowledge?: string;
239
- /** Turns: [0] = State (task_state + signals), [1..N] = History. */
256
+ /** History turns only — the stable, cacheable message prefix. */
240
257
  turns: Message[];
258
+ /**
259
+ * Volatile State turn (task_state + signals), rebuilt every call. Providers
260
+ * render it after the cacheable history (Anthropic: after the cache breakpoint;
261
+ * OpenAI-family: prepended, preserving order). Absent when produced by an
262
+ * older binding that has not been rebuilt — then the State turn is still inside
263
+ * `turns[0]` and providers render `turns` as-is.
264
+ */
265
+ stateTurn?: Message;
266
+ /**
267
+ * P1-E: count of leading `turns` forming the frozen prefix — byte-stable until the next
268
+ * compaction. The Anthropic provider pins a deep cache breakpoint at this boundary (a long-lived
269
+ * cache that survives many turns and is immune to the 20-block lookback miss on heavy tool turns)
270
+ * and rolls the other breakpoint at the tail. Absent (older binding, or no distinct frozen region
271
+ * yet) ⇒ the provider falls back to the rolling-pair placement.
272
+ */
273
+ frozenPrefixLen?: number;
241
274
  }
242
275
  /**
243
276
  * Runtime execution policy advertised by a provider.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/sdk",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "description": "DeepStrike Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@anthropic-ai/sdk": "^0.99.0",
23
- "@deepstrike/core": "0.2.11",
23
+ "@deepstrike/core": "0.2.12",
24
24
  "@google/generative-ai": "^0.24.1",
25
25
  "openai": "^5.23.2"
26
26
  },