@yanlinglabs/winter-agent-sdk 0.0.24 → 0.0.28

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/dist/index.d.ts CHANGED
@@ -20,14 +20,14 @@ export { WinterSDKError, CLIConnectionError, ProcessError, ResultError, Protocol
20
20
  export { resolveRuntimeExecutable, defaultSpawn } from "./transport.js";
21
21
  export type { SpawnedRuntimeProcess, SpawnRuntimeOptions, SpawnClaudeCodeProcess } from "./transport.js";
22
22
  export type { RuntimeConfig, RuntimeHooksConfig, RuntimeHookMatcherGroup, SandboxSettingsConfig } from "./protocol/config.js";
23
- export type { McpServerConfigForProcessTransport, AgentMcpServerSpec, RuntimeAgentDefinition } from "./protocol/config.js";
23
+ export type { McpServerConfigForProcessTransport, McpVersionNegotiation, AgentMcpServerSpec, RuntimeAgentDefinition } from "./protocol/config.js";
24
24
  export { encodeFrame, decodeFrame, splitFrames, ProtocolError } from "./protocol/codec.js";
25
25
  export { PROTOCOL_VERSION } from "./protocol/frames.js";
26
26
  export { SDK_VERSION } from "./version.js";
27
27
  export { MESSAGING_CONTROL_SUBTYPES, MESSAGING_CONTROL_SUBTYPE_LIST, MESSAGING_HOST_REQUEST_SUBTYPES, MESSAGING_RUNTIME_REQUEST_SUBTYPES, resolveFacetTarget } from "./protocol/messaging.js";
28
28
  export { isRuntimeAddress, isGlobalAgentMessage, isDeliveryOutcome, isListedRuntimeObjectArray, isPermissionClassLabel, isMessagingDeliverRequest, isMessagingChildRequest, isMessagingSubscribeIdleRequest, isMessagingReadNotificationsRequest, isMessagingNotificationsPage, isMessagingIdleNoticePayload, isNotificationRecord, } from "./protocol/messaging.js";
29
29
  export type { MessagingControlSubtype, MessagingDeliverRequest, MessagingChildRequest, MessagingSubscribeIdleRequest, MessagingSenderClassResponse, MessagingReadNotificationsRequest, MessagingNotificationsPage, MessagingIdleNoticePayload, } from "./protocol/messaging.js";
30
- export type { ProtocolVersion, WinterFrame, SdkMessage as ProtocolSdkMessage, InitFrame, UserFrame, DataFrame, ControlRequestFrame, ControlResponseFrame, ControlCancelRequestFrame, WireResultUsage, UnknownFrame, SDKHookStartedMessage, SDKHookProgressMessage, SDKHookResponseMessage, SDKPermissionDeniedMessage, SDKPermissionDenial, SDKTaskStartedMessage, SDKTaskNotificationMessage, SDKTaskUpdatedMessage, SDKTaskProgressMessage, SDKBackgroundTasksChangedMessage, SDKLocalCommandOutputMessage, BackgroundTaskMessage, SDKCompactBoundaryMessage, SDKSessionStateChangedMessage, WireContentBlock, WireStreamEvent, WireStreamEventDelta, SDKPartialAssistantMessage, SDKAssistantMessageError, SDKAPIRetryMessage, SDKRateLimitEvent, SDKRateLimitInfo, SDKAuthStatusMessage, SDKThinkingTokensMessage, SDKModelRefusalFallbackMessage, SDKModelRefusalNoFallbackMessage, SDKReasoningSummaryMessage, SDKModelSwitchMessage, SDKContinuityWarningMessage, } from "./protocol/frames.js";
30
+ export type { ProtocolVersion, WinterFrame, SdkMessage as ProtocolSdkMessage, InitFrame, UserFrame, DataFrame, ControlRequestFrame, ControlResponseFrame, ControlCancelRequestFrame, WireResultUsage, UnknownFrame, SDKHookStartedMessage, SDKHookProgressMessage, SDKHookResponseMessage, SDKPermissionDeniedMessage, SDKPermissionDenial, SDKTaskStartedMessage, SDKTaskNotificationMessage, SDKTaskUpdatedMessage, SDKTaskProgressMessage, SDKBackgroundTasksChangedMessage, SDKLocalCommandOutputMessage, BackgroundTaskMessage, SDKCompactBoundaryMessage, SDKSessionStateChangedMessage, SDKInformationalMessage, WireContentBlock, WireStreamEvent, WireStreamEventDelta, SDKPartialAssistantMessage, SDKAssistantMessageError, SDKAPIRetryMessage, SDKRateLimitEvent, SDKRateLimitInfo, SDKAuthStatusMessage, SDKThinkingTokensMessage, SDKModelRefusalFallbackMessage, SDKModelRefusalNoFallbackMessage, SDKReasoningSummaryMessage, SDKModelSwitchMessage, SDKContinuityWarningMessage, } from "./protocol/frames.js";
31
31
  export { resolveWinterHome, resolveKeychainServiceForProfile, isUnset } from "./paths/home.js";
32
32
  export { transcriptProjectKey, TRANSCRIPT_PROJECT_KEY_MAX_LENGTH, isVendorCompliantProjectKey } from "./paths/project-key.js";
33
33
  export { compatibilityKeys } from "./paths/keys.js";
@@ -50,7 +50,7 @@ export type { PermissionMode, PermissionBehavior, PermissionRuleValue } from "./
50
50
  export type { PermissionUpdate, PermissionUpdateDestination, RuleSource } from "./permissions/types.js";
51
51
  export type { CanUseTool, PermissionResult, PermissionDecisionClassification, PermissionRequestPayload } from "./permissions/types.js";
52
52
  export { HOOK_EVENTS } from "./permissions/types.js";
53
- export type { HookEvent, HookEventName, HookSource, HookPermissionDecision, BaseHookInput, PreToolUseHookInput, PostToolUseHookInput, PostToolUseFailureHookInput, UserPromptSubmitHookInput, StopHookInput, SessionStartHookInput, SessionEndHookInput, NotificationHookInput, PermissionRequestHookInput, PermissionDeniedHookInput, GenericHookInput, HookInput, AsyncHookJSONOutput, SyncHookJSONOutput, HookJSONOutput, PreToolUseHookSpecificOutput, PostToolUseHookSpecificOutput, PostToolUseFailureHookSpecificOutput, UserPromptSubmitHookSpecificOutput, StopHookSpecificOutput, SessionStartHookSpecificOutput, NotificationHookSpecificOutput, PermissionRequestHookSpecificOutput, PermissionDeniedHookSpecificOutput, GenericHookSpecificOutput, HookSpecificOutput, HookCallback, HookCallbackMatcher, HookInvocationPayload, } from "./permissions/types.js";
53
+ export type { HookEvent, HookEventName, HookSource, HookPermissionDecision, BaseHookInput, McpToolProvenance, PreToolUseHookInput, PostToolUseHookInput, PostToolUseFailureHookInput, UserPromptSubmitHookInput, StopHookInput, SessionStartHookInput, SessionEndHookInput, NotificationHookInput, PermissionRequestHookInput, PermissionDeniedHookInput, SubagentStartHookInput, SubagentStopHookInput, GenericHookInput, HookInput, AsyncHookJSONOutput, SyncHookJSONOutput, HookJSONOutput, PreToolUseHookSpecificOutput, PostToolUseHookSpecificOutput, PostToolUseFailureHookSpecificOutput, UserPromptSubmitHookSpecificOutput, StopHookSpecificOutput, SubagentStartHookSpecificOutput, SubagentStopHookSpecificOutput, SessionStartHookSpecificOutput, NotificationHookSpecificOutput, PermissionRequestHookSpecificOutput, PermissionDeniedHookSpecificOutput, GenericHookSpecificOutput, HookSpecificOutput, HookCallback, HookCallbackMatcher, HookInvocationPayload, } from "./permissions/types.js";
54
54
  export { CATALOG_TAG_RENAMES } from "@yanlinglabs/winter-provider-catalog";
55
55
  export { PluginManagerError, listMarketplaces, addMarketplace, removeMarketplace, updateMarketplace, installPlugin, uninstallPlugin, setPluginEnabled, updatePlugin, listPlugins } from "./plugins/manage.js";
56
56
  export type { PluginScope, PluginManagerOptions, MarketplaceInfo, InstalledPlugin, PluginListing } from "./plugins/manage.js";
package/dist/index.js CHANGED
@@ -139,7 +139,7 @@ class ProcessError extends WinterSDKError {
139
139
  class ResultError extends ProcessError {
140
140
  result;
141
141
  constructor(result) {
142
- super(result.terminal_reason === "api_error" ? `provider request failed: ${result.result ?? "unknown provider error"}` : `result error: ${result.subtype}`);
142
+ super(result.terminal_reason === "api_error" ? `provider request failed: ${result.result ?? "unknown provider error"}` : result.is_error === true && typeof result.terminal_reason === "string" && result.terminal_reason.length > 0 ? `${result.terminal_reason}: ${result.result ?? result.subtype}` : `result error: ${result.subtype}`);
143
143
  this.result = result;
144
144
  this.name = "ResultError";
145
145
  }
@@ -488,7 +488,8 @@ function buildRuntimeHooksConfig(hooks) {
488
488
  hookCount: group.hooks.length,
489
489
  ...group.timeout !== undefined ? { timeoutSec: group.timeout } : {},
490
490
  source: "sdk",
491
- ...hookNames.some((n) => n !== null) ? { hookNames } : {}
491
+ ...hookNames.some((n) => n !== null) ? { hookNames } : {},
492
+ ...group.failClosed === true ? { failClosed: true } : {}
492
493
  };
493
494
  });
494
495
  }
@@ -503,6 +504,8 @@ function buildHookInput(req, cwd) {
503
504
  ...req.agentID !== undefined ? { agent_id: req.agentID } : {},
504
505
  hook_event_name: req.event,
505
506
  ...req.toolName !== undefined ? { tool_name: req.toolName } : {},
507
+ ...req.mcpServerName !== undefined ? { mcp_server_name: req.mcpServerName } : {},
508
+ ...req.mcpToolName !== undefined ? { mcp_tool_name: req.mcpToolName } : {},
506
509
  ...req.input !== undefined ? { tool_input: req.input } : {},
507
510
  ...req.toolUseID !== undefined ? { tool_use_id: req.toolUseID } : {},
508
511
  ...payload
@@ -517,7 +520,7 @@ function makeHookHandler(hooks, cwd, abortController) {
517
520
  });
518
521
  });
519
522
  }
520
- return async (payload) => {
523
+ return async (payload, handlerCtx) => {
521
524
  const req = payload;
522
525
  const callback = byId.get(req.hookId);
523
526
  if (!callback) {
@@ -528,6 +531,10 @@ function makeHookHandler(hooks, cwd, abortController) {
528
531
  controller.abort();
529
532
  else
530
533
  abortController?.signal.addEventListener("abort", () => controller.abort(), { once: true });
534
+ if (handlerCtx?.signal.aborted === true)
535
+ controller.abort();
536
+ else
537
+ handlerCtx?.signal.addEventListener("abort", () => controller.abort(), { once: true });
531
538
  const input = buildHookInput(req, cwd);
532
539
  let output;
533
540
  try {
@@ -619,6 +626,7 @@ function query(args) {
619
626
  ...options.enableFileCheckpointing !== undefined ? { enableFileCheckpointing: options.enableFileCheckpointing } : {},
620
627
  ...options.contextWindowTokens !== undefined ? { contextWindowTokens: options.contextWindowTokens } : {},
621
628
  ...options.compactionThreshold !== undefined ? { compactionThreshold: options.compactionThreshold } : {},
629
+ ...options.promptCacheTtl !== undefined ? { promptCacheTtl: options.promptCacheTtl } : {},
622
630
  ...options.trustedWorkspace !== undefined ? { trustedWorkspace: options.trustedWorkspace } : {},
623
631
  ...options.plansDirectory !== undefined ? { plansDirectory: options.plansDirectory } : {},
624
632
  ...options.outputStyle !== undefined ? { outputStyle: options.outputStyle } : {},
@@ -630,6 +638,7 @@ function query(args) {
630
638
  ...options.includePartialMessages !== undefined ? { includePartialMessages: options.includePartialMessages } : {},
631
639
  ...options.maxBudgetUsd !== undefined ? { maxBudgetUsd: options.maxBudgetUsd } : {},
632
640
  ...options.providerStallTimeoutMs !== undefined ? { providerStallTimeoutMs: options.providerStallTimeoutMs } : {},
641
+ ...options.maxOutputTokens !== undefined ? { maxOutputTokens: options.maxOutputTokens } : {},
633
642
  ...brand.keychainService !== WINTER_BRAND2.keychainService || options.keychainService !== undefined ? { keychainService: brand.keychainService } : {},
634
643
  ...options.autoClassifier !== undefined ? { autoClassifier: options.autoClassifier } : {},
635
644
  ...options.advisor !== undefined ? { advisor: options.advisor } : {},
@@ -902,6 +911,14 @@ function query(args) {
902
911
  gen.setModel = async (model) => {
903
912
  await sendControlRequest("set_model", model !== undefined ? { model } : {});
904
913
  };
914
+ gen.setEffort = async (effort) => {
915
+ await sendControlRequest("set_effort", effort !== undefined ? { effort } : {});
916
+ };
917
+ gen.compact = async (opts) => {
918
+ const payload = await sendControlRequest("compact", opts?.customInstructions !== undefined ? { custom_instructions: opts.customInstructions } : {});
919
+ const retained = typeof payload === "object" && payload !== null ? payload.retained_count : undefined;
920
+ return { retainedCount: typeof retained === "number" ? retained : 0 };
921
+ };
905
922
  gen.supportedModels = async () => {
906
923
  const payload = await sendControlRequest("list_models", undefined);
907
924
  return Array.isArray(payload) ? payload : [];
@@ -1021,7 +1038,7 @@ function query(args) {
1021
1038
  return gen;
1022
1039
  }
1023
1040
  // src/version.ts
1024
- var SDK_VERSION = "0.0.24";
1041
+ var SDK_VERSION = "0.0.28";
1025
1042
  // src/paths/project-key.ts
1026
1043
  var TRANSCRIPT_PROJECT_KEY_MAX_LENGTH = 64;
1027
1044
  var VENDOR_PROJECT_KEY_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
package/dist/options.d.ts CHANGED
@@ -191,6 +191,15 @@ export interface Options {
191
191
  sessionStore?: SessionStore;
192
192
  contextWindowTokens?: number;
193
193
  compactionThreshold?: number;
194
+ /**
195
+ * WS-23 -- DISCLOSED WINTER option: how long the provider keeps this session's cached SYSTEM prompt.
196
+ * `"5m"` (the default, the vendor's own) or `"1h"` (written at twice the input price, worth it where
197
+ * idle gaps of 5-60 minutes are common: https://platform.claude.com/docs/en/build-with-claude/prompt-caching#1-hour-cache-duration).
198
+ * Applies to models whose catalog row documents prompt caching; the conversation's own rolling
199
+ * breakpoint stays at 5 minutes, which is the order the vendor requires (longer TTLs first). The
200
+ * host's choice; resolved runtime-side, so absent is byte-identical to before.
201
+ */
202
+ promptCacheTtl?: "5m" | "1h";
194
203
  trustedWorkspace?: boolean;
195
204
  plansDirectory?: string;
196
205
  outputStyle?: string;
@@ -269,6 +278,14 @@ export interface Options {
269
278
  maxBudgetUsd?: number;
270
279
  /** DISCLOSED WINTER option (R6-6): a stream silent for this long aborts as a typed `ProviderStallError`. Absent means DEFAULT_PROVIDER_STALL_TIMEOUT_MS. */
271
280
  providerStallTimeoutMs?: number;
281
+ /**
282
+ * DISCLOSED WINTER option (WS-23): the output-token ceiling (`max_tokens` on the Anthropic dialect)
283
+ * every main-loop generation asks for. Absent means the adapter's own default -- on a Claude row,
284
+ * 64000 capped at the row's declared maximum. A value above the row's maximum is refused typed,
285
+ * before the request. Forwarded as `TurnRequest.maxOutputTokens`, which an adapter treats as an
286
+ * explicit request (it wins over every default).
287
+ */
288
+ maxOutputTokens?: number;
272
289
  /** DISCLOSED WINTER option (R6-10): the macOS Keychain service every `{ kind: "keychain" }` ref resolves under. Absent means DEFAULT_KEYCHAIN_SERVICE. */
273
290
  keychainService?: string;
274
291
  /** DISCLOSED WINTER option (R6-14): the permission classifier's own model/credential, resolved through the SAME selection path as the session model. With none configured the worker serves only a `classifierEligible` model, else Manual fallback — never a silent weakening. */
@@ -101,13 +101,17 @@ export interface BaseHookInput {
101
101
  };
102
102
  }
103
103
  export type HookPermissionDecision = "allow" | "ask" | "deny" | "defer";
104
- export interface PreToolUseHookInput extends BaseHookInput {
104
+ export interface McpToolProvenance {
105
+ mcp_server_name?: string;
106
+ mcp_tool_name?: string;
107
+ }
108
+ export interface PreToolUseHookInput extends BaseHookInput, McpToolProvenance {
105
109
  hook_event_name: "PreToolUse";
106
110
  tool_name: string;
107
111
  tool_input: unknown;
108
112
  tool_use_id: string;
109
113
  }
110
- export interface PostToolUseHookInput extends BaseHookInput {
114
+ export interface PostToolUseHookInput extends BaseHookInput, McpToolProvenance {
111
115
  hook_event_name: "PostToolUse";
112
116
  tool_name: string;
113
117
  tool_input: unknown;
@@ -115,7 +119,7 @@ export interface PostToolUseHookInput extends BaseHookInput {
115
119
  tool_use_id: string;
116
120
  duration_ms?: number;
117
121
  }
118
- export interface PostToolUseFailureHookInput extends BaseHookInput {
122
+ export interface PostToolUseFailureHookInput extends BaseHookInput, McpToolProvenance {
119
123
  hook_event_name: "PostToolUseFailure";
120
124
  tool_name: string;
121
125
  tool_input: unknown;
@@ -154,25 +158,39 @@ export interface NotificationHookInput extends BaseHookInput {
154
158
  title?: string;
155
159
  notification_type: string;
156
160
  }
157
- export interface PermissionRequestHookInput extends BaseHookInput {
161
+ export interface PermissionRequestHookInput extends BaseHookInput, McpToolProvenance {
158
162
  hook_event_name: "PermissionRequest";
159
163
  tool_name: string;
160
164
  tool_input: unknown;
161
165
  permission_suggestions?: PermissionUpdate[];
162
166
  }
163
- export interface PermissionDeniedHookInput extends BaseHookInput {
167
+ export interface PermissionDeniedHookInput extends BaseHookInput, McpToolProvenance {
164
168
  hook_event_name: "PermissionDenied";
165
169
  tool_name: string;
166
170
  tool_input: unknown;
167
171
  tool_use_id: string;
168
172
  reason: string;
169
173
  }
174
+ export interface SubagentStartHookInput extends BaseHookInput {
175
+ hook_event_name: "SubagentStart";
176
+ agent_id: string;
177
+ agent_type: string;
178
+ }
179
+ export interface SubagentStopHookInput extends BaseHookInput {
180
+ hook_event_name: "SubagentStop";
181
+ stop_hook_active: boolean;
182
+ agent_id: string;
183
+ agent_transcript_path: string;
184
+ agent_type: string;
185
+ last_assistant_message?: string;
186
+ }
170
187
  export interface GenericHookInput extends BaseHookInput {
171
188
  hook_event_name: string;
172
189
  }
173
- export type HookInput = PreToolUseHookInput | PostToolUseHookInput | PostToolUseFailureHookInput | UserPromptSubmitHookInput | StopHookInput | SessionStartHookInput | SessionEndHookInput | NotificationHookInput | PermissionRequestHookInput | PermissionDeniedHookInput | GenericHookInput;
190
+ export type HookInput = PreToolUseHookInput | PostToolUseHookInput | PostToolUseFailureHookInput | UserPromptSubmitHookInput | StopHookInput | SessionStartHookInput | SessionEndHookInput | NotificationHookInput | PermissionRequestHookInput | PermissionDeniedHookInput | SubagentStartHookInput | SubagentStopHookInput | GenericHookInput;
174
191
  export interface AsyncHookJSONOutput {
175
192
  async: true;
193
+ /** Milliseconds the background run may take (the runtime's default is 10 minutes). */
176
194
  asyncTimeout?: number;
177
195
  }
178
196
  export interface PreToolUseHookSpecificOutput {
@@ -203,6 +221,14 @@ export interface StopHookSpecificOutput {
203
221
  hookEventName: "Stop";
204
222
  additionalContext?: string;
205
223
  }
224
+ export interface SubagentStartHookSpecificOutput {
225
+ hookEventName: "SubagentStart";
226
+ additionalContext?: string;
227
+ }
228
+ export interface SubagentStopHookSpecificOutput {
229
+ hookEventName: "SubagentStop";
230
+ additionalContext?: string;
231
+ }
206
232
  export interface SessionStartHookSpecificOutput {
207
233
  hookEventName: "SessionStart";
208
234
  additionalContext?: string;
@@ -236,7 +262,7 @@ export interface GenericHookSpecificOutput {
236
262
  additionalContext?: string;
237
263
  [key: string]: unknown;
238
264
  }
239
- export type HookSpecificOutput = PreToolUseHookSpecificOutput | PostToolUseHookSpecificOutput | PostToolUseFailureHookSpecificOutput | UserPromptSubmitHookSpecificOutput | StopHookSpecificOutput | SessionStartHookSpecificOutput | NotificationHookSpecificOutput | PermissionRequestHookSpecificOutput | PermissionDeniedHookSpecificOutput | GenericHookSpecificOutput;
265
+ export type HookSpecificOutput = PreToolUseHookSpecificOutput | PostToolUseHookSpecificOutput | PostToolUseFailureHookSpecificOutput | UserPromptSubmitHookSpecificOutput | StopHookSpecificOutput | SubagentStartHookSpecificOutput | SubagentStopHookSpecificOutput | SessionStartHookSpecificOutput | NotificationHookSpecificOutput | PermissionRequestHookSpecificOutput | PermissionDeniedHookSpecificOutput | GenericHookSpecificOutput;
240
266
  export interface SyncHookJSONOutput {
241
267
  continue?: boolean;
242
268
  suppressOutput?: boolean;
@@ -255,6 +281,15 @@ export interface HookCallbackMatcher {
255
281
  matcher?: string;
256
282
  hooks: HookCallback[];
257
283
  timeout?: number;
284
+ /**
285
+ * WS-23: FAIL CLOSED. Default off, so a hook that errors stays a non-blocking error exactly as
286
+ * before. When true, and the event is `PreToolUse` or `PermissionRequest`, a callback that throws,
287
+ * times out or returns a malformed output DENIES the call, with a reason naming the hook -- the
288
+ * posture a SECURITY hook needs (a floor that crashes must not wave the call through). Every hook
289
+ * in this matcher shares it, like `timeout`. Ignored on every other event: none of them decides a
290
+ * call, so there is nothing for "closed" to mean there.
291
+ */
292
+ failClosed?: boolean;
258
293
  }
259
294
  export interface HookInvocationPayload {
260
295
  event: string;
@@ -263,6 +298,10 @@ export interface HookInvocationPayload {
263
298
  agentID?: string;
264
299
  toolUseID?: string;
265
300
  toolName?: string;
301
+ /** WS-24: for an MCP tool, the connected server that registered `toolName` -- see `McpToolProvenance`. */
302
+ mcpServerName?: string;
303
+ /** WS-24: for an MCP tool, the tool's own name on that server -- see `McpToolProvenance`. */
304
+ mcpToolName?: string;
266
305
  input?: Record<string, unknown>;
267
306
  payload?: unknown;
268
307
  policyVersion: string;
@@ -78,6 +78,7 @@ export interface RuntimeHookMatcherGroup {
78
78
  timeoutSec?: number;
79
79
  source: HookSource;
80
80
  hookNames?: Array<string | null>;
81
+ failClosed?: boolean;
81
82
  }
82
83
  export type RuntimeHooksConfig = Partial<Record<string, RuntimeHookMatcherGroup[]>>;
83
84
  export interface SandboxSettingsConfig {
@@ -103,6 +104,22 @@ export interface McpServerToolPolicy {
103
104
  permission_policy?: "always_allow" | "always_ask" | "always_deny";
104
105
  org_max_permission?: "allow" | "ask" | "blocked";
105
106
  }
107
+ /**
108
+ * WS-23, WINTER-OWNED (no counterpart on the pinned official shape): how the runtime's MCP client
109
+ * negotiates the protocol revision with ONE server (MCP TS SDK v2, protocol revision 2026-07-28).
110
+ *
111
+ * - `"legacy"` -- the plain 2025 `initialize` handshake, byte-identical to the v1 client.
112
+ * - `"auto"` -- probe `server/discover` first; a server that offers 2026-07-28 gets the modern era,
113
+ * anything else falls back to `initialize`.
114
+ * - `{ pin: "<revision>" }` -- the modern era at exactly that revision, or the connect fails (typed).
115
+ *
116
+ * Absent means the per-transport default the runtime owns (`mcp/client.ts`'s
117
+ * `resolveVersionNegotiation`): `"auto"` for `http`, `"legacy"` for `stdio` and `sse`. The negotiated
118
+ * revision is reported per server on the `mcp_status` control response.
119
+ */
120
+ export type McpVersionNegotiation = "legacy" | "auto" | {
121
+ pin: string;
122
+ };
106
123
  export interface McpStdioServerConfig {
107
124
  type?: "stdio";
108
125
  command: string;
@@ -110,6 +127,7 @@ export interface McpStdioServerConfig {
110
127
  env?: Record<string, string>;
111
128
  timeout?: number;
112
129
  alwaysLoad?: boolean;
130
+ versionNegotiation?: McpVersionNegotiation;
113
131
  }
114
132
  export interface McpHttpServerConfig {
115
133
  type: "http";
@@ -118,6 +136,7 @@ export interface McpHttpServerConfig {
118
136
  tools?: McpServerToolPolicy[];
119
137
  timeout?: number;
120
138
  alwaysLoad?: boolean;
139
+ versionNegotiation?: McpVersionNegotiation;
121
140
  }
122
141
  export interface McpSSEServerConfig {
123
142
  type: "sse";
@@ -126,6 +145,7 @@ export interface McpSSEServerConfig {
126
145
  tools?: McpServerToolPolicy[];
127
146
  timeout?: number;
128
147
  alwaysLoad?: boolean;
148
+ versionNegotiation?: McpVersionNegotiation;
129
149
  }
130
150
  export interface WireMcpToolDefinition {
131
151
  name: string;
@@ -299,6 +319,8 @@ export interface RuntimeConfig {
299
319
  enableFileCheckpointing?: boolean;
300
320
  contextWindowTokens?: number;
301
321
  compactionThreshold?: number;
322
+ /** WS-23: the system prompt's cache lifetime (`Options.promptCacheTtl`); absent means the runtime's default, 5 minutes. */
323
+ promptCacheTtl?: "5m" | "1h";
302
324
  trustedWorkspace?: boolean;
303
325
  plansDirectory?: string;
304
326
  outputStyle?: string;
@@ -332,6 +354,8 @@ export interface RuntimeConfig {
332
354
  includePartialMessages?: boolean;
333
355
  maxBudgetUsd?: number;
334
356
  providerStallTimeoutMs?: number;
357
+ /** WS-23: `Options.maxOutputTokens`, carried to every main-loop `TurnRequest`. See its own doc. */
358
+ maxOutputTokens?: number;
335
359
  keychainService?: string;
336
360
  autoClassifier?: AutoClassifierConfig;
337
361
  advisor?: AdvisorConfig;
@@ -4,6 +4,7 @@ export declare const PROTOCOL_VERSION: "1.0";
4
4
  export interface WireMcpServerStatus {
5
5
  name: string;
6
6
  status: string;
7
+ protocolVersion?: string;
7
8
  }
8
9
  export interface InitFrame {
9
10
  type: "init";
@@ -57,8 +58,9 @@ export interface ControlResponseFrame {
57
58
  * adapters send `{type: "ephemeral"}` with no ttl), so `ephemeral_5m_input_tokens` equals
58
59
  * `cache_creation_input_tokens` and `ephemeral_1h_input_tokens` is 0;
59
60
  * - `server_tool_use`: Winter's WebSearch/WebFetch run client-side, never as billed server tools: 0/0;
60
- * - `output_tokens_details.thinking_tokens`: 0 -- providers' reasoning-token counts are not threaded
61
- * through Winter's usage yet (they are included in `output_tokens`);
61
+ * - `output_tokens_details.thinking_tokens`: the Responses family's reasoning-token count (WS-24
62
+ * follow-up 1) when the turn's provider reported one, else 0 -- always a SUBSET of `output_tokens`,
63
+ * never added on top. Anthropic reports no separate count, so a Claude-only turn stays 0;
62
64
  * - `service_tier: "standard"`, `inference_geo: ""`, `iterations: []`, `speed: "standard"`: the
63
65
  * pinned EMPTY_USAGE's own values.
64
66
  */
@@ -82,6 +84,19 @@ export interface WireResultUsage {
82
84
  inference_geo: string;
83
85
  iterations: unknown[];
84
86
  speed: "standard" | "fast";
87
+ /**
88
+ * WS-23 -- WINTER-ONLY, additive, present only when there is something to say: each generation of
89
+ * this turn whose provider reported where its prompt prefix diverged from the previous request
90
+ * (Anthropic's `diagnostics.cache_miss_reason`: `type`, in Anthropic's own vocabulary only, and the
91
+ * estimated `missed_input_tokens` it cost), and/or that it dropped replayed thinking blocks
92
+ * (`thinking_blocks_dropped`, from `input_transformations` -- its own field, never a `type`). claude
93
+ * has no such field.
94
+ */
95
+ cache_misses?: Array<{
96
+ type?: string;
97
+ missed_input_tokens?: number;
98
+ thinking_blocks_dropped?: number;
99
+ }>;
85
100
  }
86
101
  export interface ControlCancelRequestFrame {
87
102
  type: "control_cancel_request";
@@ -582,8 +597,13 @@ export interface SDKContinuityWarningMessage {
582
597
  * ANOTHER provider for which no credential is configured (Ruling E-1 / R-E3) -- the child then
583
598
  * runs on a deferred-refusal provider whose first generation is R6-F's result with no request,
584
599
  * never the parent's provider with a foreign model id on the parent's wire.
600
+ *
601
+ * WS-23 (reasoning-state) adds three, each shown to the user by the host: `model_switch_lossy` at a
602
+ * switch whose loss class is `warned-lossy`; `switch_compaction` when the conversation is summarized
603
+ * before a switch to a model that cannot hold it; `reasoning_state_unsaved` when a turn's reasoning
604
+ * records could not be written after one retry (the thinking is then kept inline in the transcript).
585
605
  */
586
- warning: "provider_state_missing" | "provider_state_deleted" | "cross_domain_replay_dropped" | "sidecar_unreadable" | "child_provider_refused";
606
+ warning: "provider_state_missing" | "provider_state_deleted" | "cross_domain_replay_dropped" | "sidecar_unreadable" | "child_provider_refused" | "model_switch_lossy" | "switch_compaction" | "reasoning_state_unsaved";
587
607
  detail: string;
588
608
  anchor_uuid?: string;
589
609
  uuid: string;
@@ -607,6 +627,23 @@ export interface SDKSessionStateChangedMessage {
607
627
  session_id: string;
608
628
  [k: string]: unknown;
609
629
  }
630
+ /**
631
+ * WS-23: claude 2.1.282's `SDKInformationalMessage` -- "generic text banner emitted by the loop --
632
+ * non-error status lines, hook feedback (e.g. a UserPromptSubmit hook's block reason)". Winter had no
633
+ * text-notice frame at all; this is the one a hook's `systemMessage`, a blocked prompt's reason and a
634
+ * hook's `continue: false` ride to the host. `prevent_continuation` is set when the notice is the
635
+ * reason the turn is ending.
636
+ */
637
+ export interface SDKInformationalMessage {
638
+ type: "system";
639
+ subtype: "informational";
640
+ content: string;
641
+ level: "info" | "notice" | "suggestion" | "warning";
642
+ tool_use_id?: string;
643
+ prevent_continuation?: boolean;
644
+ uuid: string;
645
+ session_id: string;
646
+ }
610
647
  export type SdkMessage = {
611
648
  type: "system";
612
649
  subtype: "init";
@@ -631,7 +668,7 @@ export type SdkMessage = {
631
668
  */
632
669
  agents?: string[];
633
670
  [k: string]: unknown;
634
- } | SDKHookStartedMessage | SDKHookProgressMessage | SDKHookResponseMessage | SDKPermissionDeniedMessage | SDKStatusMessage | SDKCompactBoundaryMessage | SDKSessionStateChangedMessage | BackgroundTaskMessage | SDKPartialAssistantMessage | SDKAPIRetryMessage | SDKRateLimitEvent | SDKAuthStatusMessage | SDKThinkingTokensMessage | SDKModelRefusalFallbackMessage | SDKModelRefusalNoFallbackMessage | SDKReasoningSummaryMessage | SDKModelSwitchMessage | SDKContinuityWarningMessage | {
671
+ } | SDKHookStartedMessage | SDKHookProgressMessage | SDKHookResponseMessage | SDKPermissionDeniedMessage | SDKStatusMessage | SDKCompactBoundaryMessage | SDKSessionStateChangedMessage | SDKInformationalMessage | BackgroundTaskMessage | SDKPartialAssistantMessage | SDKAPIRetryMessage | SDKRateLimitEvent | SDKAuthStatusMessage | SDKThinkingTokensMessage | SDKModelRefusalFallbackMessage | SDKModelRefusalNoFallbackMessage | SDKReasoningSummaryMessage | SDKModelSwitchMessage | SDKContinuityWarningMessage | {
635
672
  type: "assistant";
636
673
  message: {
637
674
  content: Array<{
@@ -661,7 +698,7 @@ export type SdkMessage = {
661
698
  is_error?: boolean;
662
699
  result?: string;
663
700
  structured_output?: unknown;
664
- terminal_reason?: "structured_output_retry_exhausted" | "api_error" | string;
701
+ terminal_reason?: "structured_output_retry_exhausted" | "api_error" | "refusal" | "prompt_too_long" | "pause_turn_limit" | string;
665
702
  api_error_status?: number | null;
666
703
  /** THIS turn's main-loop usage -- claude's `result.usage` (dist-session fixes C1); see `WireResultUsage`. */
667
704
  usage?: WireResultUsage;
package/dist/query.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { SdkMessage as RuntimeSdkMessage } from "./protocol/frames.js";
2
- import type { AccountInfo, AgentInfo, ModelInfo, ModelFamilyListing, RewindFilesResult } from "./protocol/config.js";
2
+ import type { AccountInfo, AgentInfo, EffortLevel, ModelInfo, ModelFamilyListing, RewindFilesResult } from "./protocol/config.js";
3
3
  import { type Options } from "./options.js";
4
4
  import type { PermissionMode, PermissionResult } from "./permissions/types.js";
5
5
  import { type DeliveryOutcome, type GlobalAgentMessage, type ListedRuntimeObject, type PermissionClassLabel } from "./messaging/index.js";
@@ -118,6 +118,36 @@ export interface SessionMessagingFacet {
118
118
  export interface Query extends AsyncGenerator<SdkMessage> {
119
119
  interrupt(): Promise<void>;
120
120
  setModel(model?: string): Promise<void>;
121
+ /**
122
+ * WS-23 -- WINTER-ONLY, additive: change the session's effort level while it runs. Applied at the
123
+ * next quiescent boundary (immediately when idle), exactly like `setModel`. Omitted, `null` or
124
+ * `'default'` resets to the level the session started with.
125
+ *
126
+ * On a model whose catalog row documents per-message effort (Claude Fable 5.1, Opus 5.5, Opus 5)
127
+ * the change rides a mid-conversation `system` message and the cached prompt prefix survives it;
128
+ * elsewhere it is a new top-level value, which restarts the provider's prompt cache. A level the
129
+ * current model does not document rejects with an `invalid_effort` error.
130
+ *
131
+ * claude 2.1.282 has no method for this (it changes effort through its `apply_flag_settings`
132
+ * control request); it rides Winter's own `set_effort` control subtype.
133
+ */
134
+ setEffort(effort?: EffortLevel | null): Promise<void>;
135
+ /**
136
+ * WS-23 -- WINTER-ONLY, additive: compact the conversation NOW, on the model the session is live on,
137
+ * and resolve once it has finished (`retainedCount`: the messages kept beside the summary). A host
138
+ * calls it before a switch to another provider whose model cannot hold the conversation, so the model
139
+ * being left writes the summary. Rejects with `busy` while a turn (or another compaction) runs, and
140
+ * with `compaction_failed` when there was nothing to compact or the summarizer failed.
141
+ *
142
+ * OPTIONAL on the interface (every `Query` this package returns has it): a host's own structural
143
+ * `Query` double -- the router's test peers, a daemon's fakes -- keeps type-checking without it, and a
144
+ * caller checks for it before calling.
145
+ */
146
+ compact?(opts?: {
147
+ customInstructions?: string;
148
+ }): Promise<{
149
+ retainedCount: number;
150
+ }>;
121
151
  /**
122
152
  * Phase 6 Task 10 (derived-shapes-p6 item (d), `sdk.d.ts:2566`): the models this session may select.
123
153
  *
@@ -18,12 +18,23 @@ export interface SettingsHookHandler {
18
18
  /** `"command"` is the only shape a settings file can express; see buildHookEntriesFromSettings. */
19
19
  type?: string;
20
20
  command?: string;
21
- /** SECONDS (HookCallbackMatcher.timeout's pinned unit) -- converted to ms exactly once, at entry-build time. */
21
+ /** SECONDS (HookCallbackMatcher.timeout's pinned unit) -- converted to ms exactly once, at entry-build time. For an `async` handler, its background run's timeout. */
22
22
  timeout?: number;
23
+ /** WS-23: fail CLOSED on PreToolUse/PermissionRequest (an error, a timeout or malformed output denies the call). Only a literal `true`. */
24
+ failClosed?: boolean;
25
+ /**
26
+ * WS-24: run in the BACKGROUND -- the event never waits, the hook can never allow or deny anything, and
27
+ * what it later says (`systemMessage`, `additionalContext`) reaches the model at the next safe point as
28
+ * a reminder. Refused (the hook stays synchronous, and the refusal is reported) on a fail-closed
29
+ * PreToolUse/PermissionRequest hook. Only a literal `true`.
30
+ */
31
+ async?: boolean;
23
32
  }
24
33
  export interface SettingsHookMatcherGroup {
25
34
  matcher?: string;
26
35
  hooks?: SettingsHookHandler[];
36
+ /** WS-23: `failClosed` for every handler in the group. */
37
+ failClosed?: boolean;
27
38
  }
28
39
  /** Open-keyed for the same reason RuntimeHooksConfig is (protocol/config.ts): unknown event names are accepted, preserved and inert. */
29
40
  export type SettingsHooksConfig = Partial<Record<string, SettingsHookMatcherGroup[]>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yanlinglabs/winter-agent-sdk",
3
- "version": "0.0.24",
3
+ "version": "0.0.28",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "engines": {
@@ -45,15 +45,15 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@yanlinglabs/winter-provider-catalog": "0.0.24"
48
+ "@yanlinglabs/winter-provider-catalog": "0.0.28"
49
49
  },
50
50
  "optionalDependencies": {
51
- "@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.24"
51
+ "@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.28"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^26.4.0",
55
- "winter-agent-runtime": "0.0.24",
56
- "@yanlinglabs/winter-conformance": "0.0.24"
55
+ "@yanlinglabs/winter-agent-runtime": "0.0.28",
56
+ "@yanlinglabs/winter-conformance": "0.0.28"
57
57
  },
58
58
  "scripts": {}
59
59
  }