@deepstrike/sdk 0.2.60 → 0.2.62

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/dist/index.d.ts +2 -0
  2. package/dist/index.js +1 -0
  3. package/dist/kernel.d.ts +4 -0
  4. package/dist/os/public.d.ts +1 -1
  5. package/dist/os/public.js +1 -1
  6. package/dist/providers/anthropic-adapter.d.ts +13 -1
  7. package/dist/providers/anthropic-adapter.js +106 -20
  8. package/dist/providers/anthropic.d.ts +1 -0
  9. package/dist/providers/anthropic.js +10 -3
  10. package/dist/providers/base.d.ts +2 -2
  11. package/dist/providers/base.js +7 -5
  12. package/dist/providers/catalog.js +5 -20
  13. package/dist/providers/factories.js +17 -7
  14. package/dist/providers/gemini-adapter.js +6 -14
  15. package/dist/providers/model-registry.d.ts +22 -1
  16. package/dist/providers/model-registry.js +72 -8
  17. package/dist/providers/ollama-adapter.js +2 -2
  18. package/dist/providers/openai-chat.js +4 -6
  19. package/dist/providers/openai-responses-adapter.js +12 -10
  20. package/dist/providers/openai-responses.d.ts +6 -1
  21. package/dist/providers/openai-responses.js +33 -0
  22. package/dist/providers/protocol-adapter.d.ts +6 -1
  23. package/dist/providers/protocol-adapter.js +6 -2
  24. package/dist/providers/provider-error.js +5 -1
  25. package/dist/providers/request-plan.d.ts +4 -1
  26. package/dist/providers/request-plan.js +25 -1
  27. package/dist/providers/usage-normalizer.js +58 -15
  28. package/dist/runtime/canonical-kernel-step.d.ts +2 -2
  29. package/dist/runtime/canonical-kernel-step.js +180 -232
  30. package/dist/runtime/kernel-doctor.d.ts +36 -0
  31. package/dist/runtime/kernel-doctor.js +60 -0
  32. package/dist/runtime/kernel-step.d.ts +11 -4
  33. package/dist/runtime/kernel-step.js +20 -0
  34. package/dist/runtime/provider-replay.d.ts +4 -0
  35. package/dist/runtime/provider-replay.js +15 -1
  36. package/dist/runtime/runner.d.ts +6 -5
  37. package/dist/runtime/runner.js +103 -43
  38. package/dist/runtime/session-log.d.ts +12 -0
  39. package/dist/types.d.ts +8 -5
  40. package/package.json +3 -3
@@ -9,6 +9,7 @@ import type { ExecutionPlane } from "./execution-plane.js";
9
9
  import type { RunGroup } from "./run-group.js";
10
10
  import { type MemoryPolicy, type ResourceQuota } from "../kernel.js";
11
11
  import type { AgentRunSpec, MilestoneCheckResult, MilestoneContract, MilestonePolicy, WorkflowSpec, WorkflowOutcome } from "../types/agent.js";
12
+ export declare function stableSemanticArchiveName(effectId: string): string;
12
13
  import { type SubAgentOrchestrator } from "./sub-agent-orchestrator.js";
13
14
  import { type ReducerRegistry } from "./reducers.js";
14
15
  import { type GovernancePolicy } from "../governance.js";
@@ -56,11 +57,7 @@ export interface TurnMetrics {
56
57
  inputTokens: number;
57
58
  /** Tokens served from the prompt cache this turn (Anthropic `cache_read_input_tokens`). */
58
59
  cacheReadTokens: number;
59
- /** I1: per-slot attribution of `cacheReadTokens`. Anthropic reports a single cache-read total,
60
- * not a per-block breakdown — this field is a pro-rata estimate over the slots that actually
61
- * carried a `cache_control` breakpoint on the request. Missing / empty when the provider does
62
- * not honor `cache_control` (OpenAI-family auto-cache) or when no breakpoints were placed.
63
- * Useful for diagnosing which slot is buying the cache hit when comparing strategies. */
60
+ /** Provider-authoritative per-slot attribution, when the endpoint reports one. */
64
61
  cacheReadTokensBySlot?: {
65
62
  system?: number;
66
63
  tools?: number;
@@ -68,6 +65,10 @@ export interface TurnMetrics {
68
65
  };
69
66
  /** Tokens written to the prompt cache this turn (Anthropic `cache_creation_input_tokens`). */
70
67
  cacheCreationTokens: number;
68
+ cacheTelemetryStatus?: "measured" | "unavailable";
69
+ cacheTelemetrySource?: "anthropic_usage" | "openai_prompt_details" | "deepseek_prompt_cache" | "gemini_usage";
70
+ requestFingerprint?: string;
71
+ stablePrefixFingerprint?: string;
71
72
  }
72
73
  /** O5: decision returned by `onToolCall` — `block: true` denies this call before it executes; the
73
74
  * `reason` is fed back to the model as a governance-denied tool result (so it can redirect). */
@@ -7,8 +7,17 @@ import { peekProviderReplay, seedProviderReplayFromEvents } from "./provider-rep
7
7
  import { sanitizeReplayText } from "./replay-sanitize.js";
8
8
  import { buildLlmCompletedEvent, buildRunTerminalEvent, buildWorkflowNodeCompletedEvent, buildWorkflowNodesSubmittedEvent, } from "./session-repair.js";
9
9
  import { KernelPrimitivesDashboard } from "./kernel-primitives-dashboard.js";
10
- import { capabilityMarker, capabilitySkill, capabilityTool, capabilityCommandMount, capabilityCommandUnmount, entropySampleFromObservation, messageToKernelMessage, skillMetadataToKernel, taskUpdateToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
10
+ import { capabilityMarker, capabilitySkill, capabilityTool, capabilityCommandMount, capabilityCommandUnmount, archivePresentationFromObservations, entropySampleFromObservation, messageToKernelMessage, skillMetadataToKernel, taskUpdateToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
11
11
  import { CanonicalKernelRejectedError, CanonicalRunnerRuntime, canonicalKernelAction, canonicalKernelApply, canonicalKernelMaybeAction, canonicalStartAgent, canonicalStartWorkflow, } from "./canonical-kernel-step.js";
12
+ export function stableSemanticArchiveName(effectId) {
13
+ const stableEffectId = effectId.replace(/[^a-zA-Z0-9._:-]/g, "_");
14
+ return `page-out-${stableEffectId || "unknown"}`;
15
+ }
16
+ function compressionAction(action) {
17
+ return action === "snip_compact" || action === "micro_compact" || action === "context_collapse" || action === "auto_compact"
18
+ ? action
19
+ : undefined;
20
+ }
12
21
  import { agentRunSpecToKernel, MILESTONE_UNVERIFIED_REASON, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowBudgetNote, workflowNodeSpecToKernel, workflowNodeOutcomeFromKernel, workflowNodeStatusFromTermination, workflowNodeToManifest, workflowNodeToSpec, workflowSpecToKernel, } from "../types/agent.js";
13
22
  import { defaultSubAgentOrchestrator } from "./sub-agent-orchestrator.js";
14
23
  import { extractJsonValue, schemaInstruction, schemaRetryInstruction, validateAgainstSchema, } from "./output-schema.js";
@@ -1575,6 +1584,8 @@ export class RuntimeRunner {
1575
1584
  let turnOutputTokens = 0;
1576
1585
  let turnCacheReadTokens = 0;
1577
1586
  let turnCacheCreationTokens = 0;
1587
+ let turnCacheTelemetryStatus = "unavailable";
1588
+ let turnCacheTelemetrySource;
1578
1589
  let turnCacheReadBySlot;
1579
1590
  let turnStopReason;
1580
1591
  const providerPlan = createProviderRequestPlanForProvider(this.opts.provider, context, tools, ext);
@@ -1640,9 +1651,36 @@ export class RuntimeRunner {
1640
1651
  // P0-C: capture the prompt-cache split for the tool-gating hit-rate baseline.
1641
1652
  turnCacheReadTokens = usageEvt.cacheReadInputTokens ?? 0;
1642
1653
  turnCacheCreationTokens = usageEvt.cacheCreationInputTokens ?? 0;
1654
+ turnCacheTelemetryStatus = usageEvt.cacheTelemetryStatus
1655
+ ?? usageEvt.providerUsage?.cacheTelemetryStatus
1656
+ ?? ((usageEvt.cacheReadInputTokens ?? 0) > 0 || (usageEvt.cacheCreationInputTokens ?? 0) > 0
1657
+ ? "measured"
1658
+ : "unavailable");
1659
+ turnCacheTelemetrySource = usageEvt.cacheTelemetrySource ?? usageEvt.providerUsage?.cacheTelemetrySource;
1643
1660
  // I1: per-slot attribution forwarded into TurnMetrics. Undefined when the provider
1644
1661
  // doesn't honor cache_control (OpenAI-family auto-cache).
1645
1662
  turnCacheReadBySlot = usageEvt.cacheReadInputTokensBySlot;
1663
+ // spc_024-06: postflight observed input is the authority (INV-024-08). Feed it back
1664
+ // as a durable measurement fact for this exact request fingerprint so replay reuses
1665
+ // the observed truth instead of re-counting (or trusting the preflight estimate).
1666
+ if (turnInputTokens > 0) {
1667
+ const postflight = recordPromptMeasurement(providerPlan, {
1668
+ inputTokens: turnInputTokens,
1669
+ source: { kind: "postflight" },
1670
+ confidence: "exact",
1671
+ });
1672
+ recordedMeasurements.set(providerPlan.fingerprint, postflight);
1673
+ await this.opts.sessionLog.append(sessionId, {
1674
+ kind: "prompt_measured",
1675
+ turn: runtime.turn(),
1676
+ measurement: {
1677
+ requestFingerprint: postflight.requestFingerprint,
1678
+ inputTokens: postflight.inputTokens,
1679
+ source: postflight.source,
1680
+ confidence: postflight.confidence,
1681
+ },
1682
+ });
1683
+ }
1646
1684
  // Phase 4: stop_reason drives the kernel's max-output-tokens recovery. The closing
1647
1685
  // usage frame carries it; keep the last non-empty value seen this turn.
1648
1686
  if (usageEvt.stopReason)
@@ -1782,6 +1820,10 @@ export class RuntimeRunner {
1782
1820
  inputTokens: turnInputTokens,
1783
1821
  cacheReadTokens: turnCacheReadTokens,
1784
1822
  cacheCreationTokens: turnCacheCreationTokens,
1823
+ cacheTelemetryStatus: turnCacheTelemetryStatus,
1824
+ ...(turnCacheTelemetrySource ? { cacheTelemetrySource: turnCacheTelemetrySource } : {}),
1825
+ requestFingerprint: providerPlan.fingerprint,
1826
+ stablePrefixFingerprint: providerPlan.stablePrefixFingerprint,
1785
1827
  ...(turnCacheReadBySlot ? { cacheReadTokensBySlot: turnCacheReadBySlot } : {}),
1786
1828
  });
1787
1829
  }
@@ -1881,6 +1923,7 @@ export class RuntimeRunner {
1881
1923
  await this.logMemoryRetrievalResult(sessionId, hits);
1882
1924
  }
1883
1925
  else if (action.kind === "archive_page_out") {
1926
+ const archiveEffectId = action.effectId;
1884
1927
  const archiveMeta = this.activePageOutArchive
1885
1928
  ?? this.pendingPageOutArchives.shift()
1886
1929
  ?? {
@@ -1908,8 +1951,8 @@ export class RuntimeRunner {
1908
1951
  error = formatToolError(cause);
1909
1952
  }
1910
1953
  const archived = action.archived ?? [];
1911
- const archiveAction = compressionAction(action.action) ?? "auto_compact";
1912
- const archiveTier = action.tier;
1954
+ const archiveAction = archiveMeta.action ?? "auto_compact";
1955
+ const archiveTier = archiveMeta.tier;
1913
1956
  const compressedSeq = archiveMeta.compressedSeq;
1914
1957
  if (!error)
1915
1958
  this.activePageOutArchive = undefined;
@@ -1926,7 +1969,7 @@ export class RuntimeRunner {
1926
1969
  taskScope.spawn("compressed-summary-upgrade", upgrade);
1927
1970
  }
1928
1971
  if (archiveTier === "semantic" && archived.length > 0) {
1929
- taskScope.spawn("semantic-page-out", () => this.archiveSemanticPageOut(archived, archiveAction, sessionId));
1972
+ taskScope.spawn("semantic-page-out", () => this.archiveSemanticPageOut(archived, archiveAction, sessionId, archiveEffectId));
1930
1973
  }
1931
1974
  }
1932
1975
  }
@@ -2483,7 +2526,12 @@ export class RuntimeRunner {
2483
2526
  const compressedSeq = await this.opts.sessionLog.append(sessionId, event);
2484
2527
  if (event.kind === "compressed") {
2485
2528
  if ((obs.archived_count ?? 0) > 0) {
2486
- this.pendingPageOutArchives.push({ archiveStart: nextArchiveStart, compressedSeq });
2529
+ const archivePresentation = archivePresentationFromObservations([obs]);
2530
+ this.pendingPageOutArchives.push({
2531
+ archiveStart: nextArchiveStart,
2532
+ compressedSeq,
2533
+ ...archivePresentation,
2534
+ });
2487
2535
  }
2488
2536
  nextArchiveStart = compressedSeq + 1;
2489
2537
  }
@@ -2496,37 +2544,58 @@ export class RuntimeRunner {
2496
2544
  }
2497
2545
  return nextArchiveStart;
2498
2546
  }
2499
- async archiveSemanticPageOut(archived, action, sessionId) {
2547
+ async archiveSemanticPageOut(archived, action, sessionId, effectId = "unknown") {
2500
2548
  if (!this.opts.memoryStore || !this.opts.agentId || !this.opts.memoryScope)
2501
2549
  return;
2502
- const summary = this.opts.memorySummarizer
2503
- ? await this.opts.memorySummarizer.summarize(archived, { action })
2504
- : await summarizeForLongTermMemory(this.opts.memoryProvider ?? this.opts.provider, archived, this.opts.memorySystemPrompt);
2505
- // P2 write-funnel: route through the ONE gated WriteMemory syscall so validation,
2506
- // the rolling write quota, dedup, and the memory_written audit all apply. Score is
2507
- // advisory (0.6) — an automatic summary must never outrank curated content.
2508
- const now = Date.now();
2509
- const name = `page-out-${now}`;
2510
- await this.writeMemory({
2511
- record_id: `${this.opts.memoryScope.tenant_id}:${this.opts.memoryScope.namespace}:project:${name}`,
2512
- scope: this.opts.memoryScope,
2513
- name,
2514
- kind: "project",
2515
- content: summary,
2516
- description: `auto summary of ${action ?? "compaction"} archive`,
2517
- provenance: {
2518
- session_id: sessionId,
2519
- author: "extraction",
2520
- trust: "untrusted",
2521
- evidence_refs: [],
2522
- },
2523
- created_at: now,
2524
- updated_at: now,
2525
- recall_count: 0,
2526
- confidence: 0.6,
2527
- links: [],
2528
- pinned: false,
2529
- }, { sessionId, agentId: this.opts.agentId });
2550
+ await this.opts.sessionLog.append(sessionId, {
2551
+ kind: "semantic_archive_pending",
2552
+ effect_id: effectId,
2553
+ ...(action ? { action } : {}),
2554
+ });
2555
+ try {
2556
+ const summary = this.opts.memorySummarizer
2557
+ ? await this.opts.memorySummarizer.summarize(archived, { action })
2558
+ : await summarizeForLongTermMemory(this.opts.memoryProvider ?? this.opts.provider, archived, this.opts.memorySystemPrompt);
2559
+ // P2 write-funnel: route through the ONE gated WriteMemory syscall so validation,
2560
+ // the rolling write quota, dedup, and the memory_written audit all apply. Score is
2561
+ // advisory (0.6) — an automatic summary must never outrank curated content.
2562
+ const now = Date.now();
2563
+ const name = stableSemanticArchiveName(effectId);
2564
+ const recordId = `${this.opts.memoryScope.tenant_id}:${this.opts.memoryScope.namespace}:project:${name}`;
2565
+ await this.writeMemory({
2566
+ record_id: recordId,
2567
+ scope: this.opts.memoryScope,
2568
+ name,
2569
+ kind: "project",
2570
+ content: summary,
2571
+ description: `auto summary of ${action ?? "compaction"} archive`,
2572
+ provenance: {
2573
+ session_id: sessionId,
2574
+ author: "extraction",
2575
+ trust: "untrusted",
2576
+ evidence_refs: [],
2577
+ },
2578
+ created_at: now,
2579
+ updated_at: now,
2580
+ recall_count: 0,
2581
+ confidence: 0.6,
2582
+ links: [],
2583
+ pinned: false,
2584
+ }, { sessionId, agentId: this.opts.agentId });
2585
+ await this.opts.sessionLog.append(sessionId, {
2586
+ kind: "semantic_archive_completed",
2587
+ effect_id: effectId,
2588
+ record_id: recordId,
2589
+ });
2590
+ }
2591
+ catch (error) {
2592
+ await this.opts.sessionLog.append(sessionId, {
2593
+ kind: "semantic_archive_failed",
2594
+ effect_id: effectId,
2595
+ error: formatToolError(error),
2596
+ });
2597
+ throw error;
2598
+ }
2530
2599
  }
2531
2600
  async upgradeCompressedSummary(sessionId, compressedSeq, archived, action, runtime) {
2532
2601
  const summary = await this.opts.asyncSummarizer.summarize(archived, action);
@@ -2601,15 +2670,6 @@ function attachmentsToKernelMessage(parts) {
2601
2670
  });
2602
2671
  return { role: "user", content };
2603
2672
  }
2604
- function compressionAction(action) {
2605
- if (action === "snip_compact" ||
2606
- action === "micro_compact" ||
2607
- action === "context_collapse" ||
2608
- action === "auto_compact") {
2609
- return action;
2610
- }
2611
- return undefined;
2612
- }
2613
2673
  async function summarizeForLongTermMemory(provider, archived, systemPrompt) {
2614
2674
  const transcript = archived
2615
2675
  .map(m => `${m.role}: ${m.content}`)
@@ -98,6 +98,18 @@ export type SessionEvent = {
98
98
  tier_hint?: string;
99
99
  message_count?: number;
100
100
  archive_ref?: string;
101
+ } | {
102
+ kind: "semantic_archive_pending";
103
+ effect_id: string;
104
+ action?: string;
105
+ } | {
106
+ kind: "semantic_archive_completed";
107
+ effect_id: string;
108
+ record_id: string;
109
+ } | {
110
+ kind: "semantic_archive_failed";
111
+ effect_id: string;
112
+ error: string;
101
113
  } | {
102
114
  kind: "page_in";
103
115
  turn: number;
package/dist/types.d.ts CHANGED
@@ -151,10 +151,9 @@ export interface UsageEvent extends StreamEvent {
151
151
  cacheReadInputTokens?: number;
152
152
  /** Prompt tokens written to cache this request (billed ~1.25x). Subset of inputTokens. */
153
153
  cacheCreationInputTokens?: number;
154
- /** I1: per-slot pro-rata attribution of `cacheReadInputTokens`. Estimated, not authoritative —
155
- * Anthropic returns a single cache-read total, so the SDK divides it evenly across the slots
156
- * that carried a `cache_control` breakpoint on the request. Missing when the provider doesn't
157
- * honor `cache_control` (OpenAI-family auto-cache) or when no breakpoints were placed. */
154
+ cacheTelemetryStatus?: CacheTelemetryStatus;
155
+ cacheTelemetrySource?: CacheTelemetrySource;
156
+ /** Reserved for provider-authoritative per-slot data. DeepStrike does not estimate this field. */
158
157
  cacheReadInputTokensBySlot?: {
159
158
  system?: number;
160
159
  tools?: number;
@@ -339,12 +338,16 @@ export interface ProviderUsage {
339
338
  outputTokens: number;
340
339
  cacheReadInputTokens?: number;
341
340
  cacheCreationInputTokens?: number;
341
+ cacheTelemetryStatus?: CacheTelemetryStatus;
342
+ cacheTelemetrySource?: CacheTelemetrySource;
342
343
  /** Output tokens spent on hidden reasoning (OpenAI `completion_tokens_details.reasoning_tokens` /
343
344
  * Responses `output_tokens_details.reasoning_tokens`). A SUBSET of `outputTokens`, not additional
344
345
  * — vendors that don't report a separate count (Anthropic, Gemini via this SDK) leave this unset
345
346
  * rather than guessing. */
346
347
  reasoningTokens?: number;
347
348
  }
349
+ export type CacheTelemetryStatus = "measured" | "unavailable";
350
+ export type CacheTelemetrySource = "anthropic_usage" | "openai_prompt_details" | "deepseek_prompt_cache" | "gemini_usage";
348
351
  /** Node-side mirror of the reserved Rust `context::measurement` types — where a
349
352
  * preflight token count came from. Field names/shape intentionally match the Rust
350
353
  * `MeasurementSource` enum (`kind`-tagged, snake_case variant names) so the two sides can be
@@ -523,7 +526,7 @@ export interface LLMProvider {
523
526
  * capability remains directly callable, but no dispatch trigger is enabled until request
524
527
  * fingerprinting and durable measurement semantics are defined.
525
528
  */
526
- countTokens?(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<PromptMeasurement>;
529
+ countTokens?(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, state?: ProviderRunState): Promise<PromptMeasurement>;
527
530
  complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
528
531
  stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, state?: ProviderRunState,
529
532
  /** #2-B-ii: when provided, a preempting `InterruptNow` (or `interrupt()`) aborts the in-flight
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/sdk",
3
- "version": "0.2.60",
3
+ "version": "0.2.62",
4
4
  "description": "DeepStrike Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -72,9 +72,9 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "@anthropic-ai/sdk": "^0.99.0",
75
- "@deepstrike/core": "0.2.60",
75
+ "@deepstrike/core": "0.2.62",
76
76
  "@google/generative-ai": "^0.24.1",
77
- "openai": "^5.23.2"
77
+ "openai": "^7.5.0"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@types/jest": "^30.0.0",