@yanlinglabs/winter-agent-sdk 0.0.15 → 0.0.17

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 CHANGED
@@ -68,6 +68,95 @@ plus two canonical standing-server twins, and `@yanlinglabs/winter-runtime-sdk`
68
68
  definitions under Claude's built-in names. Handlers return `{ text, isError? }` for each host to
69
69
  wrap in its own result shape.
70
70
 
71
+ ## Environment variables and settings
72
+
73
+ The runtime child reads a handful of environment variables at spawn/per-turn, plus a few
74
+ `Options`/`RuntimeConfig` fields. Every variable name below is `WINTER_`-prefixed for Winter's own
75
+ build (`BrandProfile.envPrefix`); a rebranded host reads the identical suffix under its own prefix.
76
+
77
+ | Variable | Default | Effect |
78
+ | --- | --- | --- |
79
+ | `WINTER_DISABLE_BACKGROUND_TASKS` | off | A hard kill switch with two effects together: it drops `run_in_background` from the Agent tool's own advertised schema entirely, and it forces every subagent spawn to the foreground unconditionally (outranking a definition's own `background: true`, a fork, and an explicit `run_in_background: true` alike). |
80
+ | `WINTER_BACKGROUND_BY_DEFAULT` | on (background) | A softer opt-out than the kill switch above: a falsy value (`0`/`false`/`no`/`off`, case-insensitive) restores the pre-0.0.16 default (an unflagged spawn runs in the FOREGROUND) without removing `run_in_background` from the schema — the model can still ask for either explicitly either way. `Options.backgroundByDefault` (see below) wins over this variable in either direction when both are set. |
81
+ | `WINTER_PRINT_BG_WAIT_CEILING_MS` | `600000` (10 minutes) | How long a closed-input session holds its result for a still-running background agent/workflow before sweeping it as stopped. `0` waits indefinitely. |
82
+ | `WINTER_EMIT_SESSION_STATE_EVENTS` | off | Truthy (`1`/`true`) emits `system/session_state_changed` frames (`running`/`idle`) as a turn starts and ends. Absent, the frame stream is unchanged from before this existed. |
83
+ | `WINTER_DISABLE_GIT_INSTRUCTIONS` | off | Truthy disables the git status/instructions section of the system prompt outright, overriding `Settings.includeGitInstructions` in either direction. A falsy value (`0`/`false`/`no`/`off`) explicitly re-enables it even when the setting says otherwise. |
84
+ | `WINTER_DISABLE_EXPLORE_INHERIT_CAP` | off | Truthy opts a first-party Anthropic session out of the Explore built-in's own model cap (which otherwise caps a Fable-tier session's Explore spawn down to Opus). |
85
+ | `WINTER_FORK_SUBAGENT` | off | Truthy enables `subagent_type: "fork"` for the session (mirrors `CLAUDE_CODE_FORK_SUBAGENT`). `Options.forkSubagent` (below) wins over this variable in either direction. |
86
+ | `WINTER_WEB_FETCH_AGENT` | off | Truthy makes the `web-fetch` built-in agent type available (off by default, like claude's own). |
87
+ | `WINTER_MAX_WEB_SEARCHES_PER_SESSION` | `200` | How many `WebSearch` calls one session may make, counted before each search and shared with every descendant subagent (the analogue of `CLAUDE_CODE_MAX_WEB_SEARCHES_PER_SESSION`). Past it, a call answers with a plain refusal result rather than an error. |
88
+ | `WINTER_AGENT_SDK_DISABLE_BUILTIN_AGENTS` | off | Truthy withholds every built-in `subagent_type` (gated or not) for the session. |
89
+ | `WINTER_DISABLE_EXPLORE_PLAN_AGENTS` | off | Truthy withholds the `Explore` and `Plan` built-ins together. |
90
+ | `WINTER_DISABLE_AGENT_VIEW` | off | Truthy withholds the `claude` catch-all built-in (mirrors `CLAUDE_CODE_DISABLE_AGENT_VIEW`). |
91
+ | `WINTER_MAX_SUBAGENT_SPAWN_DEPTH` | `3` | How many levels of subagent nesting are allowed beneath the top-level session before a spawn is refused. |
92
+ | `WINTER_MAX_CONCURRENT_SUBAGENTS` | `20` | How many subagents may run at once (across the whole nesting tree) before a spawn is refused. |
93
+
94
+ A handful of `Options`/settings fields carry the same weight as their env counterparts, and a
95
+ RuntimeConfig field always wins over its own env fallback in either direction when both are set:
96
+
97
+ - **`Settings.includeGitInstructions`** (default `true`) — the setting `WINTER_DISABLE_GIT_INSTRUCTIONS` overrides above.
98
+ - **`Options.forkSubagent`** (`boolean`, default unset → env fallback) — the RuntimeConfig field behind `WINTER_FORK_SUBAGENT`.
99
+ - **`Options.backgroundByDefault`** (`boolean`, default unset → env fallback) — the RuntimeConfig field behind `WINTER_BACKGROUND_BY_DEFAULT`, above.
100
+
101
+ `RuntimeConfig.allowedAgentTypes` (`string[]`) is a different shape of field, not a host-settable
102
+ one: there is no `Options.allowedAgentTypes` and no env fallback to win over. It exists only on the
103
+ wire `RuntimeConfig`, and the engine — never a host — populates it: when a running agent's own
104
+ definition restricts `tools` with an `Agent(a, b)` entry, `allowedAgentTypesFromTools` parses that
105
+ restriction and threads the resulting list onto the CHILD it spawns for that agent's own
106
+ `RuntimeConfig`, so the child's listing / `init.agents` / Agent-tool resolution sees only `[a, b]`,
107
+ never the full universe of types its parent session could otherwise reach. Absent (every top-level
108
+ session, and any child whose parent definition named no `Agent(...)` restriction) means
109
+ unrestricted, the behavior every session had before this field existed.
110
+
111
+ ### The built-in web tools (since 0.0.17)
112
+
113
+ `WebFetch` and `WebSearch` ship in every default `init.tools`, as copies of the pinned `claude`
114
+ runtime's own — same descriptions, same input schemas, same inner-call prompts, same output assembly.
115
+
116
+ - **`WebFetch`** takes `{url, prompt}`, fetches the page from this machine (`http` is upgraded to
117
+ `https` unconditionally, and a hostname with fewer than two dot-separated labels is refused — so
118
+ `localhost` and IPv6 literals are not fetchable, exactly as in claude), converts HTML to markdown,
119
+ and answers `prompt` over it with a small fast model. Responses are cached for 15 minutes per
120
+ session. Rules are `WebFetch(domain:<host>)`; an allow rule naming an exact host is standing consent
121
+ for that host wherever it resolves.
122
+ - **`WebSearch`** takes `{query, allowed_domains?, blocked_domains?}` and runs one inner pass over the
123
+ search backend, returning titles and urls only. The budget is 200 calls per session
124
+ (`WINTER_MAX_WEB_SEARCHES_PER_SESSION`), shared with every descendant. Its only rule form is the
125
+ bare `WebSearch`; a scoped `WebSearch(...)` in `Options.allowedTools`/`disallowedTools` throws at
126
+ startup (a settings file drops it and warns).
127
+
128
+ Withdraw either with `disallowedTools`. `WebSearch` can also be switched off at the backend with
129
+ `web.search.enabled: false`.
130
+
131
+ - **`Options.web`** — `search.enabled`, `search.authRef` (the backend key, used only once the
132
+ anonymous tier is exhausted), `search.maxSearchesPerCall` / `search.anonymousMaxSearchesPerCall`,
133
+ `fetch.digestModel` / `fetch.authRef` (the page-digest model and its own credential),
134
+ `fetch.privateAddressPolicy` (`"ask"` by default, `"deny"` / `"allow"`), and one `blockedDomains`
135
+ floor both tools honour (suffix match on a label boundary: `example.com` covers
136
+ `docs.example.com`). Every field is optional; `resolveWebToolsConfig` + `WEB_TOOLS_DEFAULTS` are
137
+ exported for a host that wants the resolved shape. **An unattended host should set
138
+ `fetch.privateAddressPolicy: "deny"`** — under the default a private or loopback target raises a real
139
+ permission prompt, and a session that cannot prompt refuses the call.
140
+ - **`Options.autoMemory`** — `enabled` and `directory` for the auto-memory section, for a host that
141
+ runs with `settingSources: []` and therefore cannot reach `autoMemoryEnabled` /
142
+ `autoMemoryDirectory` in a settings file. Precedence per field: this option, then the settings key,
143
+ then the computed default (`<home>/projects/<memory-key>/memory`, enabled). A relocated directory
144
+ under the home's own `projects/` tree stays write-denied.
145
+
146
+ Subagents inherit both.
147
+
148
+ ### The 0.0.16 background-default change
149
+
150
+ Before 0.0.16, an Agent tool call with no `run_in_background` ran in the **foreground** (this call
151
+ does not return until the spawned agent finishes). From 0.0.16 on, matching claude, the same
152
+ unflagged call runs in the **background** by default: the call returns immediately with a task id,
153
+ and the model is told about the result later as a task notification (mid-turn, or as its own
154
+ unsolicited turn). `run_in_background: false` still asks for the old, synchronous behavior on any
155
+ one call. A host that wants the *default* itself to stay foreground — without losing the
156
+ `run_in_background` field or forcing every call to name it explicitly — sets
157
+ `Options.backgroundByDefault: false` (or `WINTER_BACKGROUND_BY_DEFAULT=false`); the kill switch,
158
+ `WINTER_DISABLE_BACKGROUND_TASKS`, is unrelated and unaffected by this knob in either direction.
159
+
71
160
  ## License
72
161
 
73
162
  MIT — see [`LICENSE`](./LICENSE), which ships in the published tarball.
package/dist/index.d.ts CHANGED
@@ -4,6 +4,9 @@ export type { QueryInternal, ControlRequestHandler, ControlRequestHandlerResult
4
4
  export type { Options } from "./options.js";
5
5
  export { SYSTEM_PROMPT_DYNAMIC_BOUNDARY, DEFAULT_CONTEXT_WINDOW_TOKENS, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_PLANS_DIRECTORY, DEFAULT_OUTPUT_STYLE } from "./options.js";
6
6
  export { DEFAULT_PROVIDER_STALL_TIMEOUT_MS, DEFAULT_KEYCHAIN_SERVICE } from "./options.js";
7
+ export { WEB_TOOLS_DEFAULTS, resolveWebToolsConfig } from "./options.js";
8
+ export type { ResolvedWebToolsConfig } from "./options.js";
9
+ export type { WebToolsConfig, WebSearchConfig, WebFetchConfig, WebPrivateAddressPolicy, AutoMemoryConfig } from "./protocol/config.js";
7
10
  export type { ProviderSelection, ProviderConnectionConfig, CredentialRef, ThinkingConfig, EffortLevel, AutoClassifierConfig, AdvisorConfig, ModelInfo, AgentInfo, AccountInfo } from "./protocol/config.js";
8
11
  export type { SlotView, ActiveSlotSet, ModelFamilyListing, ModelSlotSetting, ModelRowServable } from "./protocol/config.js";
9
12
  export type { SdkPluginConfig, SystemPromptOption, SystemPromptPreset, OutputFormat, JsonSchemaOutputFormat, SkillsOption, RewindFilesResult, RewindFilesRequest, InitPluginInfo } from "./protocol/config.js";
@@ -24,7 +27,7 @@ export { SDK_VERSION } from "./version.js";
24
27
  export { MESSAGING_CONTROL_SUBTYPES, MESSAGING_CONTROL_SUBTYPE_LIST, MESSAGING_HOST_REQUEST_SUBTYPES, MESSAGING_RUNTIME_REQUEST_SUBTYPES, resolveFacetTarget } from "./protocol/messaging.js";
25
28
  export { isRuntimeAddress, isGlobalAgentMessage, isDeliveryOutcome, isListedRuntimeObjectArray, isPermissionClassLabel, isMessagingDeliverRequest, isMessagingChildRequest, isMessagingSubscribeIdleRequest, isMessagingReadNotificationsRequest, isMessagingNotificationsPage, isMessagingIdleNoticePayload, isNotificationRecord, } from "./protocol/messaging.js";
26
29
  export type { MessagingControlSubtype, MessagingDeliverRequest, MessagingChildRequest, MessagingSubscribeIdleRequest, MessagingSenderClassResponse, MessagingReadNotificationsRequest, MessagingNotificationsPage, MessagingIdleNoticePayload, } from "./protocol/messaging.js";
27
- export type { ProtocolVersion, WinterFrame, SdkMessage as ProtocolSdkMessage, InitFrame, UserFrame, DataFrame, ControlRequestFrame, ControlResponseFrame, UnknownFrame, SDKHookStartedMessage, SDKHookProgressMessage, SDKHookResponseMessage, SDKPermissionDeniedMessage, SDKPermissionDenial, SDKTaskStartedMessage, SDKTaskNotificationMessage, SDKTaskUpdatedMessage, SDKTaskProgressMessage, SDKBackgroundTasksChangedMessage, SDKLocalCommandOutputMessage, BackgroundTaskMessage, SDKCompactBoundaryMessage, 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, 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";
28
31
  export { resolveWinterHome, resolveKeychainServiceForProfile, isUnset } from "./paths/home.js";
29
32
  export { transcriptProjectKey, TRANSCRIPT_PROJECT_KEY_MAX_LENGTH, isVendorCompliantProjectKey } from "./paths/project-key.js";
30
33
  export { compatibilityKeys } from "./paths/keys.js";
package/dist/index.js CHANGED
@@ -66,6 +66,38 @@ var DEFAULT_PLANS_DIRECTORY = `${WINTER_BRAND2.projectDirName}/plans`;
66
66
  var DEFAULT_OUTPUT_STYLE = "default";
67
67
  var DEFAULT_PROVIDER_STALL_TIMEOUT_MS = 120000;
68
68
  var DEFAULT_KEYCHAIN_SERVICE = WINTER_BRAND2.keychainService;
69
+ var WEB_TOOLS_DEFAULTS = {
70
+ searchEnabled: true,
71
+ maxSearchesPerCall: 8,
72
+ anonymousMaxSearchesPerCall: 3,
73
+ privateAddressPolicy: "ask"
74
+ };
75
+ function positiveIntegerOr(value, fallback) {
76
+ return typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.floor(value) : fallback;
77
+ }
78
+ var PRIVATE_ADDRESS_POLICIES = ["allow", "ask", "deny"];
79
+ function resolveWebToolsConfig(web) {
80
+ const rawDigest = web?.fetch?.digestModel;
81
+ const digestModel = typeof rawDigest === "string" ? rawDigest.trim() : undefined;
82
+ const rawPolicy = web?.fetch?.privateAddressPolicy;
83
+ const privateAddressPolicy = PRIVATE_ADDRESS_POLICIES.find((policy) => policy === rawPolicy) ?? WEB_TOOLS_DEFAULTS.privateAddressPolicy;
84
+ const rawEnabled = web?.search?.enabled;
85
+ const rawBlocked = web?.blockedDomains;
86
+ return {
87
+ search: {
88
+ enabled: rawEnabled === undefined ? WEB_TOOLS_DEFAULTS.searchEnabled : rawEnabled === true,
89
+ ...web?.search?.authRef !== undefined ? { authRef: web.search.authRef } : {},
90
+ maxSearchesPerCall: positiveIntegerOr(web?.search?.maxSearchesPerCall, WEB_TOOLS_DEFAULTS.maxSearchesPerCall),
91
+ anonymousMaxSearchesPerCall: positiveIntegerOr(web?.search?.anonymousMaxSearchesPerCall, WEB_TOOLS_DEFAULTS.anonymousMaxSearchesPerCall)
92
+ },
93
+ fetch: {
94
+ ...digestModel !== undefined && digestModel.length > 0 ? { digestModel } : {},
95
+ ...web?.fetch?.authRef !== undefined ? { authRef: web.fetch.authRef } : {},
96
+ privateAddressPolicy
97
+ },
98
+ blockedDomains: (Array.isArray(rawBlocked) ? rawBlocked : []).filter((d) => typeof d === "string" && d.trim().length > 0)
99
+ };
100
+ }
69
101
  function isWinterMcpServerInstance(value) {
70
102
  if (typeof value !== "object" || value === null)
71
103
  return false;
@@ -579,6 +611,7 @@ function query(args) {
579
611
  ...options.agents !== undefined ? { agents: options.agents } : {},
580
612
  ...options.forwardSubagentText !== undefined ? { forwardSubagentText: options.forwardSubagentText } : {},
581
613
  ...options.forkSubagent !== undefined ? { forkSubagent: options.forkSubagent } : {},
614
+ ...options.backgroundByDefault !== undefined ? { backgroundByDefault: options.backgroundByDefault } : {},
582
615
  ...options.systemPrompt !== undefined ? { systemPrompt: options.systemPrompt } : {},
583
616
  ...options.plugins !== undefined ? { plugins: options.plugins } : {},
584
617
  ...options.skills !== undefined ? { skills: options.skills } : {},
@@ -600,6 +633,8 @@ function query(args) {
600
633
  ...brand.keychainService !== WINTER_BRAND2.keychainService || options.keychainService !== undefined ? { keychainService: brand.keychainService } : {},
601
634
  ...options.autoClassifier !== undefined ? { autoClassifier: options.autoClassifier } : {},
602
635
  ...options.advisor !== undefined ? { advisor: options.advisor } : {},
636
+ ...options.web !== undefined ? { web: options.web } : {},
637
+ ...options.autoMemory !== undefined ? { autoMemory: options.autoMemory } : {},
603
638
  brand
604
639
  };
605
640
  const command = options.spawnClaudeCodeProcess ? options.pathToClaudeCodeExecutable ?? "winter" : resolveRuntimeExecutable(options);
@@ -966,7 +1001,7 @@ function query(args) {
966
1001
  return gen;
967
1002
  }
968
1003
  // src/version.ts
969
- var SDK_VERSION = "0.0.15";
1004
+ var SDK_VERSION = "0.0.17";
970
1005
  // src/paths/project-key.ts
971
1006
  var TRANSCRIPT_PROJECT_KEY_MAX_LENGTH = 64;
972
1007
  var VENDOR_PROJECT_KEY_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
@@ -1689,6 +1724,7 @@ export {
1689
1724
  SYSTEM_PROMPT_DYNAMIC_BOUNDARY,
1690
1725
  SessionNotFoundError,
1691
1726
  TRANSCRIPT_PROJECT_KEY_MAX_LENGTH,
1727
+ WEB_TOOLS_DEFAULTS,
1692
1728
  WINTER_BRAND2 as WINTER_BRAND,
1693
1729
  WinterCompatibilitySessionStore2 as WinterCompatibilitySessionStore,
1694
1730
  WinterRpcError,
@@ -1737,6 +1773,7 @@ export {
1737
1773
  resolveRuntimeExecutable,
1738
1774
  resolveSettings,
1739
1775
  resolveSettingsDetailed,
1776
+ resolveWebToolsConfig,
1740
1777
  resolveWinterHome2 as resolveWinterHome,
1741
1778
  settingsPathFor,
1742
1779
  splitFrames,
package/dist/options.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import type { SpawnClaudeCodeProcess } from "./transport.js";
2
2
  import type { PermissionMode, CanUseTool, HookEvent, HookCallbackMatcher } from "./permissions/types.js";
3
- import type { SandboxSettingsConfig, McpServerToolPolicy, McpStdioServerConfig, McpHttpServerConfig, McpSSEServerConfig, McpSdkServerConfig, RuntimeAgentDefinition, SdkPluginConfig, SystemPromptOption, OutputFormat, SkillsOption, ProviderSelection, ThinkingConfig, EffortLevel, AutoClassifierConfig, AdvisorConfig } from "./protocol/config.js";
3
+ import type { SandboxSettingsConfig, McpServerToolPolicy, McpStdioServerConfig, McpHttpServerConfig, McpSSEServerConfig, McpSdkServerConfig, RuntimeAgentDefinition, SdkPluginConfig, SystemPromptOption, OutputFormat, SkillsOption, ProviderSelection, ThinkingConfig, EffortLevel, AutoClassifierConfig, AdvisorConfig, WebToolsConfig, WebPrivateAddressPolicy, AutoMemoryConfig, CredentialRef } from "./protocol/config.js";
4
4
  import type { SettingSource } from "./settings/types.js";
5
5
  import type { SessionStore } from "./store/session-store.js";
6
6
  import { type BrandProfile } from "./brand.js";
7
7
  export type { BrandProfile, BrandValidation } from "./brand.js";
8
8
  export type { SdkPluginConfig, SystemPromptOption, OutputFormat, JsonSchemaOutputFormat, SkillsOption } from "./protocol/config.js";
9
9
  export type { ProviderSelection, ProviderConnectionConfig, CredentialRef, ThinkingConfig, EffortLevel, AutoClassifierConfig, AdvisorConfig } from "./protocol/config.js";
10
+ export type { WebToolsConfig, WebSearchConfig, WebFetchConfig, WebPrivateAddressPolicy, AutoMemoryConfig } from "./protocol/config.js";
10
11
  export declare const SYSTEM_PROMPT_DYNAMIC_BOUNDARY = "__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__";
11
12
  export declare const DEFAULT_CONTEXT_WINDOW_TOKENS = 200000;
12
13
  export declare const DEFAULT_COMPACTION_THRESHOLD = 0.92;
@@ -14,6 +15,42 @@ export declare const DEFAULT_PLANS_DIRECTORY: string;
14
15
  export declare const DEFAULT_OUTPUT_STYLE = "default";
15
16
  export declare const DEFAULT_PROVIDER_STALL_TIMEOUT_MS = 120000;
16
17
  export declare const DEFAULT_KEYCHAIN_SERVICE: string;
18
+ /**
19
+ * Every web-tool default, spelled ONCE. A reader function resolves an absent field against this --
20
+ * no consumer writes a literal of its own.
21
+ *
22
+ * `maxSearchesPerCall: 8` is the pinned tool's own per-call bound. `anonymousMaxSearchesPerCall: 3`
23
+ * is Winter's: see `WebSearchConfig.anonymousMaxSearchesPerCall`. `privateAddressPolicy: "ask"` is
24
+ * the conservative interactive posture; a host that can never ask sets `"deny"`.
25
+ */
26
+ export declare const WEB_TOOLS_DEFAULTS: {
27
+ readonly searchEnabled: true;
28
+ readonly maxSearchesPerCall: 8;
29
+ readonly anonymousMaxSearchesPerCall: 3;
30
+ readonly privateAddressPolicy: "ask";
31
+ };
32
+ /** `WebToolsConfig` with every default applied -- what a consumer reads instead of the raw option. */
33
+ export interface ResolvedWebToolsConfig {
34
+ search: {
35
+ enabled: boolean;
36
+ authRef?: CredentialRef;
37
+ maxSearchesPerCall: number;
38
+ anonymousMaxSearchesPerCall: number;
39
+ };
40
+ fetch: {
41
+ digestModel?: string;
42
+ authRef?: CredentialRef;
43
+ privateAddressPolicy: WebPrivateAddressPolicy;
44
+ };
45
+ blockedDomains: string[];
46
+ }
47
+ /**
48
+ * THE one reader of `WebToolsConfig`. Pure, dependency-free and total: an absent block, an absent
49
+ * field, a non-positive or non-finite bound and a whitespace-only `digestModel` all resolve to the
50
+ * default rather than to a value no consumer can act on (a bound of `0` would make a tool that is
51
+ * advertised and can never search; disabling search is `search.enabled: false`).
52
+ */
53
+ export declare function resolveWebToolsConfig(web: WebToolsConfig | undefined): ResolvedWebToolsConfig;
17
54
  export interface McpSdkServerConfigWithInstance extends McpSdkServerConfig {
18
55
  instance: unknown;
19
56
  }
@@ -103,6 +140,21 @@ export interface Options {
103
140
  * `CLAUDE_CODE_FORK_SUBAGENT`), and is off when that is unset.
104
141
  */
105
142
  forkSubagent?: boolean;
143
+ /**
144
+ * I4 (fix wave): a programmatic opt-out for the Agent tool's own background default (SDK 0.0.16,
145
+ * `subagents/policy.ts`'s `resolveForegroundBackground` -- "background unless `run_in_background`
146
+ * is explicitly false"). `false` restores the 0.0.15 default (foreground) for every spawn this
147
+ * knob's stage of the chain decides; `true` is the 0.0.16 default, spelled out. Omitted = the
148
+ * runtime reads `WINTER_BACKGROUND_BY_DEFAULT` (falsy -- "0"/"false"/"no"/"off" -- restores
149
+ * foreground; anything else, including absent, keeps background), the SAME `forkSubagent`
150
+ * precedent: the field wins in either direction, the env is only the fallback.
151
+ *
152
+ * Distinct from `WINTER_DISABLE_BACKGROUND_TASKS` (which keeps its own, unrelated meaning -- a
153
+ * hard kill switch that ALSO removes `run_in_background` from the advertised schema entirely):
154
+ * this knob changes only which way an OMITTED `run_in_background` resolves, and the field stays
155
+ * on the schema either way.
156
+ */
157
+ backgroundByDefault?: boolean;
106
158
  onElicitation?: (request: {
107
159
  serverName: string;
108
160
  message: string;
@@ -231,6 +283,20 @@ export interface Options {
231
283
  * The MODEL may also come from `settings.advisor.model` (D30, hot); `Options.advisor.model` wins.
232
284
  */
233
285
  advisor?: AdvisorConfig;
286
+ /**
287
+ * DISCLOSED WINTER option: the `WebSearch` / `WebFetch` tools' configuration -- the search
288
+ * backend's fallback key and per-call bounds, the page-digest model and its credential, the
289
+ * private-address policy, and the ONE `blockedDomains` floor both tools honour. Every field is
290
+ * optional; `resolveWebToolsConfig` applies `WEB_TOOLS_DEFAULTS`. See `WebToolsConfig`.
291
+ */
292
+ web?: WebToolsConfig;
293
+ /**
294
+ * DISCLOSED WINTER option: the host's say over the auto-memory section -- whether it is on, and
295
+ * which directory it names. Wins over the settings keys, which win over the computed default; it
296
+ * is how a host that disables settings files (`settingSources: []`) still makes the session agree
297
+ * with it about where memory lives. See `AutoMemoryConfig`.
298
+ */
299
+ autoMemory?: AutoMemoryConfig;
234
300
  /**
235
301
  * DISCLOSED WINTER option (P7a, D19): THE BRAND PROFILE — every Winter-owned name this session
236
302
  * runs under, as a partial that folds onto Winter's own defaults (brand.ts's `WINTER_BRAND`).
@@ -197,6 +197,14 @@ export interface RuntimeAgentDefinition {
197
197
  * every pre-existing definition's context, unchanged.
198
198
  */
199
199
  omitProjectContext?: boolean;
200
+ /**
201
+ * SDK 0.0.16 Lane P (R3b §5): claude's `whenToUseLean` -- used in place of `description` in the
202
+ * Agent-tool listing when the session's own model takes the lean prompt (`leanModel`, computed
203
+ * by `context/agent-listing.ts`'s own caller). Set only on Winter's built-in Explore; every other
204
+ * definition (Winter's own, or a filesystem/programmatic one) has none, and the listing falls
205
+ * back to `description` exactly as it always has.
206
+ */
207
+ whenToUseLean?: string;
200
208
  }
201
209
  export interface RuntimeConfig {
202
210
  sessionId: string;
@@ -240,6 +248,16 @@ export interface RuntimeConfig {
240
248
  toolAliases?: Record<string, string>;
241
249
  agents?: Record<string, RuntimeAgentDefinition>;
242
250
  forwardSubagentText?: boolean;
251
+ /**
252
+ * SDK 0.0.16 Lane P (R3b §4): the RUNNING agent's own `Agent(a, b)` restriction, parsed from its
253
+ * `AgentDefinition.tools` entries by `subagents/definitions.ts`'s own `allowedAgentTypesFromTools`
254
+ * and threaded onto a CHILD's own RuntimeConfig at spawn (`child-engine.ts`) -- so a session
255
+ * spawned from a definition with `tools: ["*", "Agent(Explore, Plan)"]` sees only [Explore, Plan]
256
+ * in ITS OWN listing / `init.agents` / Agent-tool resolution, never the full universe of types
257
+ * this session could otherwise reach. Absent = unrestricted, the pre-existing behaviour every
258
+ * session before this field existed keeps. Pure passthrough; query.ts never interprets it.
259
+ */
260
+ allowedAgentTypes?: string[];
243
261
  agentId?: string;
244
262
  isolationPinnedCwd?: boolean;
245
263
  /**
@@ -254,6 +272,13 @@ export interface RuntimeConfig {
254
272
  * a forked worker may not fork again (claude's own refusal). Never set by `query()`.
255
273
  */
256
274
  insideFork?: boolean;
275
+ /**
276
+ * I4 (fix wave): mirrors `Options.backgroundByDefault` exactly -- see that field's own comment.
277
+ * `subagents/policy.ts`'s `resolveForegroundBackground` reads it at its own stage 5, AFTER the
278
+ * `WINTER_DISABLE_BACKGROUND_TASKS` kill switch (stage 2, unrelated and unaffected) and the
279
+ * invocation's own explicit `run_in_background` (stage 4, always wins when given).
280
+ */
281
+ backgroundByDefault?: boolean;
257
282
  systemPrompt?: SystemPromptOption;
258
283
  plugins?: SdkPluginConfig[];
259
284
  skills?: SkillsOption;
@@ -297,6 +322,10 @@ export interface RuntimeConfig {
297
322
  keychainService?: string;
298
323
  autoClassifier?: AutoClassifierConfig;
299
324
  advisor?: AdvisorConfig;
325
+ /** The wire twin of `Options.web` -- see `WebToolsConfig`. Pure passthrough; absent means every default in `WEB_TOOLS_DEFAULTS`. */
326
+ web?: WebToolsConfig;
327
+ /** The wire twin of `Options.autoMemory` -- see `AutoMemoryConfig`. Pure passthrough; absent means "settings, then the computed default". */
328
+ autoMemory?: AutoMemoryConfig;
300
329
  /**
301
330
  * P7a (D19): the RESOLVED brand profile — every Winter-owned name this session runs under.
302
331
  *
@@ -447,6 +476,139 @@ export interface AdvisorConfig {
447
476
  model: string;
448
477
  authRef?: CredentialRef;
449
478
  }
479
+ /**
480
+ * What to do when `WebFetch` is pointed at a loopback, private-range or link-local address.
481
+ *
482
+ * `"ask"` raise the ordinary permission prompt for that host before anything is fetched;
483
+ * `"deny"` refuse with a typed tool result and fetch nothing;
484
+ * `"allow"` fetch it like any public host.
485
+ *
486
+ * WHY THIS IS A HOST DECISION AND NOT A CONSTANT. A sandboxed shell has no network, so `WebFetch` is
487
+ * the only door from a session to the services on the user's own machine and LAN -- an admin page, a
488
+ * metadata endpoint. Whether that door opens silently depends on whether the session can ask a human
489
+ * at all: an interactive host can, an unattended one cannot and must refuse.
490
+ *
491
+ * WHAT `"allow"` AND AN APPROVAL CAN AND CANNOT REACH. `WebFetch` upgrades `http` to `https`
492
+ * unconditionally and refuses any hostname with fewer than two dot-separated labels -- both are the
493
+ * reference runtime's own rules, kept. So this policy governs an `https` service at an IPv4 literal
494
+ * (`https://127.0.0.1:8443/`) or at a name the URL parser leaves with two or more labels
495
+ * (`printer.local`, `api.localhost`). A plain-`http` port and every IPv6 literal (`[::1]` is one
496
+ * label) are unfetchable whatever this says -- a session pointed at one gets `Invalid URL` from the
497
+ * tool, and no approval is raised for it, because no answer could make it work.
498
+ */
499
+ export type WebPrivateAddressPolicy = "allow" | "ask" | "deny";
500
+ /** `WebSearch`'s own configuration. Every field is optional; see `WEB_TOOLS_DEFAULTS` (options.ts) for what absent means. */
501
+ export interface WebSearchConfig {
502
+ /**
503
+ * The host's explicit OFF switch for the search BACKEND. Absent means enabled.
504
+ *
505
+ * The backend's anonymous tier needs no credential, so "is a search backend usable" is `true` for
506
+ * every session by default -- which would make the tool's capability gate a constant. This is the
507
+ * one fact that can make it `false`: a host that must not let a session reach the backend at all
508
+ * (an offline deployment, a policy that forbids the third-party endpoint). With `false` the tool is
509
+ * not advertised, and a call that reaches it anyway answers with a typed refusal.
510
+ *
511
+ * NOT a substitute for `disallowedTools`, which hides a tool the runtime has; this says the
512
+ * backend behind it is not there.
513
+ */
514
+ enabled?: boolean;
515
+ /**
516
+ * A reference to the search backend's API key -- the FALLBACK, used only once the anonymous tier
517
+ * is exhausted or rate-limited. A locator, never the key: the runtime resolves it at the last
518
+ * responsible moment and accepts EITHER JSON credential material (`{"kind":"api-key","key":...}`)
519
+ * OR a bare non-empty string, because a host that shares this keychain slot with another client
520
+ * cannot change what is stored in it. Absent means anonymous-only: an exhausted quota is then a
521
+ * typed "add a key" result, never an error that ends the turn.
522
+ */
523
+ authRef?: CredentialRef;
524
+ /**
525
+ * The most backend searches ONE `WebSearch` call may run while a key is in use (the inner model
526
+ * decides how many it needs, up to this). Absent means `WEB_TOOLS_DEFAULTS.maxSearchesPerCall`.
527
+ */
528
+ maxSearchesPerCall?: number;
529
+ /**
530
+ * The same bound while the call is riding the ANONYMOUS tier. Separate, and lower by default,
531
+ * because the anonymous tier is a small shared daily allowance: eight searches per call would
532
+ * spend it in a handful of calls and push every later one onto the key (or onto the "quota
533
+ * exhausted" result when there is no key). Absent means
534
+ * `WEB_TOOLS_DEFAULTS.anonymousMaxSearchesPerCall`.
535
+ */
536
+ anonymousMaxSearchesPerCall?: number;
537
+ }
538
+ /** `WebFetch`'s own configuration. Every field is optional; see `WEB_TOOLS_DEFAULTS` (options.ts) for what absent means. */
539
+ export interface WebFetchConfig {
540
+ /**
541
+ * The model that digests a fetched page against the caller's prompt -- a provider-qualified tag
542
+ * (`<providerId>/<model>`) or a slot name, resolved through the SAME selection path as the session
543
+ * model.
544
+ *
545
+ * THE DEFAULT, stated plainly: when the host names none, the digest runs on the SESSION'S OWN
546
+ * MODEL. That is the one choice that is always resolvable and needs no second credential. There is
547
+ * deliberately no "cheapest slot" heuristic -- a family's slots are not reliably ranked
548
+ * strongest-to-weakest, so picking one by position would be a guess presented as a rule.
549
+ *
550
+ * A STATED model that cannot be resolved (unknown tag, disabled provider, no credential) is a
551
+ * typed refusal surfaced as the tool's RESULT. It is never a silent fallback onto the session's
552
+ * model: a host that named a small model did so to bound cost, and quietly spending the session
553
+ * model's price instead is the failure this field exists to prevent.
554
+ */
555
+ digestModel?: string;
556
+ /**
557
+ * The digest model's OWN credential, for a digest model on another provider than the session's
558
+ * (the cross-provider credential rule every auxiliary route follows: the route's own ref, else the
559
+ * session's material only when the provider is the same, else the target provider's
560
+ * `<providerId>:default` keychain record, else a typed `no-credential-for-provider`). The session's
561
+ * key is never sent to another provider. Ignored when `digestModel` is absent.
562
+ */
563
+ authRef?: CredentialRef;
564
+ /** See `WebPrivateAddressPolicy`. Absent means `WEB_TOOLS_DEFAULTS.privateAddressPolicy`. */
565
+ privateAddressPolicy?: WebPrivateAddressPolicy;
566
+ }
567
+ /**
568
+ * DISCLOSED WINTER option: the two web tools' configuration.
569
+ *
570
+ * `blockedDomains` sits at THIS level, not under either tool, because it is ONE list with ONE
571
+ * meaning -- the host's domain floor -- and both tools must honour it: `WebFetch` refuses a listed
572
+ * host outright, and `WebSearch` sends the list as the backend's exclusion filter on EVERY inner
573
+ * search, so a blocked domain can neither be fetched nor be surfaced as a link to fetch. Two lists
574
+ * would be two chances to update one and forget the other.
575
+ *
576
+ * MATCHING IS BY SUFFIX ON A LABEL BOUNDARY: listing `example.com` blocks `example.com` and every
577
+ * subdomain of it (`docs.example.com`), and does not block `notexample.com`. Entries are compared
578
+ * case-insensitively; a leading `*.` or `.` and a trailing `.` are ignored.
579
+ */
580
+ export interface WebToolsConfig {
581
+ search?: WebSearchConfig;
582
+ fetch?: WebFetchConfig;
583
+ blockedDomains?: string[];
584
+ }
585
+ /**
586
+ * DISCLOSED WINTER option: the host's say over the auto-memory section.
587
+ *
588
+ * WHY IT EXISTS. The runtime computes the memory directory itself and reads `autoMemoryEnabled` /
589
+ * `autoMemoryDirectory` from SETTINGS FILES only. A host that turns settings files off
590
+ * (`settingSources: []`) therefore had no way to make the session agree with it about where memory
591
+ * lives, or to turn the section off -- the two sides could only agree by computing the same path by
592
+ * coincidence.
593
+ *
594
+ * PRECEDENCE, per field: this option, then the settings key, then the computed default
595
+ * (`<home>/projects/<memory-key>/memory`, enabled).
596
+ *
597
+ * `enabled: false` the auto-memory section and its index are omitted entirely, whatever settings
598
+ * say; `enabled: true` turns it on even over a settings `false`.
599
+ * `directory` REPLACES the computed path outright, with no per-project nesting beneath it
600
+ * (`~` and a cwd-relative path are expanded exactly as the settings key's are).
601
+ * Whitespace-only counts as absent.
602
+ *
603
+ * NOTE FOR A HOST RELOCATING THE DIRECTORY: the write-permission carve-out for memory files is keyed
604
+ * to the DEFAULT `projects/<key>/memory` shape under the home. A directory elsewhere under the
605
+ * home's `projects/` tree is still write-denied; one outside the home meets no floor at all and
606
+ * follows the session's ordinary write rules.
607
+ */
608
+ export interface AutoMemoryConfig {
609
+ enabled?: boolean;
610
+ directory?: string;
611
+ }
450
612
  /**
451
613
  * The pinned `ModelInfo` (`sdk.d.ts:1261-1300`): three required fields, six optional.
452
614
  *
@@ -544,6 +544,24 @@ export interface SDKContinuityWarningMessage {
544
544
  uuid: string;
545
545
  session_id: string;
546
546
  }
547
+ /**
548
+ * SDK 0.0.16 Lane N: `notifySessionStateChanged` (pinned `sdk.d.ts`: "Mirrors notifySessionStateChanged.
549
+ * 'idle' fires after heldBackResult flushes and the bg-agent do-while exits -- authoritative turn-over
550
+ * signal"). ENV-GATED on both runtimes: the pinned binary emits it only under
551
+ * `CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS`, Winter only under `WINTER_EMIT_SESSION_STATE_EVENTS`, so a
552
+ * default session's frame stream is byte-identical with or without this variant existing.
553
+ *
554
+ * `requires_action` is declared (it is in the pinned union) but has no Winter producer: Winter's
555
+ * approval prompts ride `control_request`, not a session-state transition.
556
+ */
557
+ export interface SDKSessionStateChangedMessage {
558
+ type: "system";
559
+ subtype: "session_state_changed";
560
+ state: "idle" | "running" | "requires_action";
561
+ uuid: string;
562
+ session_id: string;
563
+ [k: string]: unknown;
564
+ }
547
565
  export type SdkMessage = {
548
566
  type: "system";
549
567
  subtype: "init";
@@ -568,7 +586,7 @@ export type SdkMessage = {
568
586
  */
569
587
  agents?: string[];
570
588
  [k: string]: unknown;
571
- } | SDKHookStartedMessage | SDKHookProgressMessage | SDKHookResponseMessage | SDKPermissionDeniedMessage | SDKStatusMessage | SDKCompactBoundaryMessage | BackgroundTaskMessage | SDKPartialAssistantMessage | SDKAPIRetryMessage | SDKRateLimitEvent | SDKAuthStatusMessage | SDKThinkingTokensMessage | SDKModelRefusalFallbackMessage | SDKModelRefusalNoFallbackMessage | SDKReasoningSummaryMessage | SDKModelSwitchMessage | SDKContinuityWarningMessage | {
589
+ } | SDKHookStartedMessage | SDKHookProgressMessage | SDKHookResponseMessage | SDKPermissionDeniedMessage | SDKStatusMessage | SDKCompactBoundaryMessage | SDKSessionStateChangedMessage | BackgroundTaskMessage | SDKPartialAssistantMessage | SDKAPIRetryMessage | SDKRateLimitEvent | SDKAuthStatusMessage | SDKThinkingTokensMessage | SDKModelRefusalFallbackMessage | SDKModelRefusalNoFallbackMessage | SDKReasoningSummaryMessage | SDKModelSwitchMessage | SDKContinuityWarningMessage | {
572
590
  type: "assistant";
573
591
  message: {
574
592
  content: Array<{
@@ -76,6 +76,11 @@ export interface Settings {
76
76
  skillListingMaxDescChars?: number;
77
77
  /** `sdk.d.ts:5503`. The listing's share of the context window (default 0.01). */
78
78
  skillListingBudgetFraction?: number;
79
+ /**
80
+ * `sdk.d.ts:5539`. SDK 0.0.16: whether the systemContext `gitStatus` snapshot is sent (default
81
+ * true). `<PREFIX>DISABLE_GIT_INSTRUCTIONS` overrides it either way.
82
+ */
83
+ includeGitInstructions?: boolean;
79
84
  /**
80
85
  * A settings-tier MCP server block. Deliberately `Record<string, unknown>` rather than a typed
81
86
  * server union: `settings/loaders/mcp-config.ts` validates each entry and `resolveMcpServerSources`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yanlinglabs/winter-agent-sdk",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
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.15"
48
+ "@yanlinglabs/winter-provider-catalog": "0.0.17"
49
49
  },
50
50
  "optionalDependencies": {
51
- "@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.15"
51
+ "@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.17"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^26.4.0",
55
- "@yanlinglabs/winter-conformance": "0.0.15",
56
- "winter-agent-runtime": "0.0.15"
55
+ "winter-agent-runtime": "0.0.17",
56
+ "@yanlinglabs/winter-conformance": "0.0.17"
57
57
  },
58
58
  "scripts": {}
59
59
  }