@yanlinglabs/winter-agent-sdk 0.0.35 → 0.0.38
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 +31 -0
- package/dist/index.js +49 -5
- package/dist/options.d.ts +23 -0
- package/dist/protocol/config.d.ts +60 -0
- package/dist/protocol/frames.d.ts +10 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -128,6 +128,37 @@ runtime's own — same descriptions, same input schemas, same inner-call prompts
|
|
|
128
128
|
Withdraw either with `disallowedTools`. `WebSearch` can also be switched off at the backend with
|
|
129
129
|
`web.search.enabled: false`.
|
|
130
130
|
|
|
131
|
+
- **`Search`** (opt-in, unreleased) takes `{query}` and returns Exa's answer mode: a written answer
|
|
132
|
+
and the pages it came from, in one call. It is offered only when `Options.tools` names it and
|
|
133
|
+
`web.search.authRef` names a key (the answer endpoint has no anonymous tier). The cited urls pass
|
|
134
|
+
the same `blockedDomains` floor, and a withheld source is counted in the result.
|
|
135
|
+
|
|
136
|
+
All three report the icon of each site they name to the HOST only, as `winter_site_icons:
|
|
137
|
+
[{url, icon_url}]` on the host-facing `tool_result` block. The model never sees it.
|
|
138
|
+
|
|
139
|
+
### Shaping the tool surface (0.0.38)
|
|
140
|
+
|
|
141
|
+
- **`Options.tools`** — claude's own option: the built-in tool set by name, or the `claude_code`
|
|
142
|
+
preset (the same as leaving it out). A visibility list: a built-in left out is not advertised, not
|
|
143
|
+
searchable, and refused at dispatch. MCP servers' tools are never filtered by it. Without `ToolSearch`
|
|
144
|
+
in it, nothing is deferred.
|
|
145
|
+
- **`Options.deferTools`** — tools that start deferred while Tool Search is active (`toolSearchEnabled`),
|
|
146
|
+
loaded through `ToolSearch` on first use. This is the only way a built-in defers.
|
|
147
|
+
- **`McpSdkServerConfig.toolNames`** — plain names for an in-process server's tools (`{ browser:
|
|
148
|
+
"Browser" }`). The model, the transcript, hooks and `canUseTool` all see the plain name. The call still
|
|
149
|
+
reaches the host as `sdk_mcp_call` with the server's own tool name, and the tool still defers like an
|
|
150
|
+
MCP tool. The `mcp__<server>__<tool>` spelling stays an equivalent identity for permission rules,
|
|
151
|
+
`disallowedTools` and hook matchers; when one of those names it, the call is evaluated under that
|
|
152
|
+
spelling, as for an alias. A plain name that collides with another tool refuses the session. The old
|
|
153
|
+
spelling also selects the tool in a model call, `ToolSearch`'s `select:` and an agent definition's
|
|
154
|
+
`tools`.
|
|
155
|
+
- **`Options.legacyToolNames`** — `{ <old name>: <current tool name> }` for a host's own renamed tool:
|
|
156
|
+
the old name keeps working in calls, `select:`, agent definitions, rules, `disallowedTools` and hook
|
|
157
|
+
matchers.
|
|
158
|
+
- **`Options.reservedMcpServerNames`** — server names only the host's own `type: "sdk"` servers may
|
|
159
|
+
take; any other server under one (settings, project, plugin, explicit non-sdk, `mcp_set_servers`) is
|
|
160
|
+
refused, and an agent definition's inline server is renamed.
|
|
161
|
+
|
|
131
162
|
- **`Options.web`** — `search.enabled`, `search.authRef` (the backend key, used only once the
|
|
132
163
|
anonymous tier is exhausted), `search.maxSearchesPerCall` / `search.anonymousMaxSearchesPerCall`,
|
|
133
164
|
`fetch.digestModel` / `fetch.authRef` (the page-digest model and its own credential),
|
package/dist/index.js
CHANGED
|
@@ -419,7 +419,8 @@ function toWireMcpServers(servers) {
|
|
|
419
419
|
type: "sdk",
|
|
420
420
|
name: cfg.name,
|
|
421
421
|
...cfg.timeout !== undefined ? { timeout: cfg.timeout } : {},
|
|
422
|
-
...isWinterMcpServerInstance(cfg.instance) ? { tools: cfg.instance.listTools() } : {}
|
|
422
|
+
...isWinterMcpServerInstance(cfg.instance) ? { tools: cfg.instance.listTools() } : {},
|
|
423
|
+
...cfg.toolNames !== undefined ? { toolNames: { ...cfg.toolNames } } : {}
|
|
423
424
|
} : cfg;
|
|
424
425
|
}
|
|
425
426
|
return out;
|
|
@@ -630,6 +631,15 @@ function makeHookHandler(hooks, cwd, abortController) {
|
|
|
630
631
|
function isModelFamilyListing(payload) {
|
|
631
632
|
return typeof payload === "object" && payload !== null && Array.isArray(payload.families);
|
|
632
633
|
}
|
|
634
|
+
function abortedBeforeSpawn() {
|
|
635
|
+
return {
|
|
636
|
+
stdin: { write() {}, end() {} },
|
|
637
|
+
stdout: async function* () {}(),
|
|
638
|
+
kill() {},
|
|
639
|
+
exited: Promise.resolve({ code: null, signal: "SIGTERM" }),
|
|
640
|
+
pid: null
|
|
641
|
+
};
|
|
642
|
+
}
|
|
633
643
|
function query(args) {
|
|
634
644
|
const { prompt, options } = args;
|
|
635
645
|
if (options.canUseTool) {
|
|
@@ -689,6 +699,10 @@ function query(args) {
|
|
|
689
699
|
...options.toolSearchEnabled !== undefined ? { toolSearchEnabled: options.toolSearchEnabled } : {},
|
|
690
700
|
...options.insideSubagent !== undefined ? { insideSubagent: options.insideSubagent } : {},
|
|
691
701
|
...options.familyMetadata !== undefined ? { familyMetadata: options.familyMetadata } : {},
|
|
702
|
+
...Array.isArray(options.tools) ? { tools: [...options.tools] } : {},
|
|
703
|
+
...options.deferTools !== undefined ? { deferTools: [...options.deferTools] } : {},
|
|
704
|
+
...options.legacyToolNames !== undefined ? { legacyToolNames: { ...options.legacyToolNames } } : {},
|
|
705
|
+
...options.reservedMcpServerNames !== undefined ? { reservedMcpServerNames: [...options.reservedMcpServerNames] } : {},
|
|
692
706
|
...options.allowDangerouslySkipPermissions !== undefined ? { allowDangerouslySkipPermissions: options.allowDangerouslySkipPermissions } : {},
|
|
693
707
|
...runtimeHooksConfig !== undefined ? { hooks: runtimeHooksConfig } : {},
|
|
694
708
|
...options.includeHookEvents !== undefined ? { includeHookEvents: options.includeHookEvents } : {},
|
|
@@ -735,8 +749,33 @@ function query(args) {
|
|
|
735
749
|
env: withTestKeychainRedirect(options.env) ?? process.env,
|
|
736
750
|
...options.abortController ? { signal: options.abortController.signal } : {}
|
|
737
751
|
};
|
|
738
|
-
const proc = (options.spawnClaudeCodeProcess ?? defaultSpawn)(spawnOptions);
|
|
752
|
+
const proc = options.abortController?.signal.aborted === true ? abortedBeforeSpawn() : (options.spawnClaudeCodeProcess ?? defaultSpawn)(spawnOptions);
|
|
739
753
|
const maxBufferSize = options.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE;
|
|
754
|
+
let killRequested = false;
|
|
755
|
+
let spawnKillEscalation;
|
|
756
|
+
const killForAbort = () => {
|
|
757
|
+
if (killRequested)
|
|
758
|
+
return;
|
|
759
|
+
killRequested = true;
|
|
760
|
+
try {
|
|
761
|
+
proc.kill();
|
|
762
|
+
} catch {}
|
|
763
|
+
spawnKillEscalation = setTimeout(() => {
|
|
764
|
+
try {
|
|
765
|
+
proc.kill("SIGKILL");
|
|
766
|
+
} catch {}
|
|
767
|
+
}, KILL_GRACE_MS);
|
|
768
|
+
spawnKillEscalation.unref?.();
|
|
769
|
+
const clear = () => clearTimeout(spawnKillEscalation);
|
|
770
|
+
proc.exited.then(clear, clear);
|
|
771
|
+
};
|
|
772
|
+
let removeSpawnAbortListener = () => {};
|
|
773
|
+
if (options.abortController !== undefined && options.abortController.signal.aborted !== true) {
|
|
774
|
+
const signal = options.abortController.signal;
|
|
775
|
+
signal.addEventListener("abort", killForAbort, { once: true });
|
|
776
|
+
removeSpawnAbortListener = () => signal.removeEventListener("abort", killForAbort);
|
|
777
|
+
proc.exited.then(removeSpawnAbortListener, removeSpawnAbortListener);
|
|
778
|
+
}
|
|
740
779
|
const pendingHostRequests = new Map;
|
|
741
780
|
let generatorTerminated = false;
|
|
742
781
|
function sendControlRequest(subtype, payload) {
|
|
@@ -877,9 +916,15 @@ function query(args) {
|
|
|
877
916
|
if (aborted)
|
|
878
917
|
return;
|
|
879
918
|
aborted = true;
|
|
919
|
+
if (killRequested)
|
|
920
|
+
return;
|
|
921
|
+
killRequested = true;
|
|
880
922
|
proc.kill();
|
|
881
923
|
killTimer = setTimeout(() => proc.kill("SIGKILL"), KILL_GRACE_MS);
|
|
882
924
|
killTimer.unref?.();
|
|
925
|
+
const timer = killTimer;
|
|
926
|
+
const clear = () => clearTimeout(timer);
|
|
927
|
+
proc.exited.then(clear, clear);
|
|
883
928
|
};
|
|
884
929
|
options.abortController?.signal.addEventListener("abort", onAbort);
|
|
885
930
|
try {
|
|
@@ -979,8 +1024,7 @@ function query(args) {
|
|
|
979
1024
|
} finally {
|
|
980
1025
|
generatorTerminated = true;
|
|
981
1026
|
options.abortController?.signal.removeEventListener("abort", onAbort);
|
|
982
|
-
|
|
983
|
-
clearTimeout(killTimer);
|
|
1027
|
+
removeSpawnAbortListener();
|
|
984
1028
|
try {
|
|
985
1029
|
proc.stdin.end();
|
|
986
1030
|
} catch {}
|
|
@@ -1136,7 +1180,7 @@ function withTestKeychainRedirect(env) {
|
|
|
1136
1180
|
return { ...env, [TEST_KEYCHAIN_ENV]: redirect };
|
|
1137
1181
|
}
|
|
1138
1182
|
// src/version.ts
|
|
1139
|
-
var SDK_VERSION = "0.0.
|
|
1183
|
+
var SDK_VERSION = "0.0.38";
|
|
1140
1184
|
// src/paths/project-key.ts
|
|
1141
1185
|
var TRANSCRIPT_PROJECT_KEY_MAX_LENGTH = 64;
|
|
1142
1186
|
var VENDOR_PROJECT_KEY_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
package/dist/options.d.ts
CHANGED
|
@@ -155,6 +155,29 @@ export interface Options {
|
|
|
155
155
|
familyMetadata?: {
|
|
156
156
|
taskNative?: boolean;
|
|
157
157
|
};
|
|
158
|
+
/**
|
|
159
|
+
* claude's own `tools` option: the BUILT-IN tool set, by name -- an array, or the `claude_code` preset
|
|
160
|
+
* (every built-in, the same as leaving it out). It is a VISIBILITY list, unlike `allowedTools` (which
|
|
161
|
+
* pre-approves): a built-in left out is not advertised, not searchable, and refused at dispatch as a
|
|
162
|
+
* tool the model was not offered. MCP servers' tools (including an in-process server's plain-named
|
|
163
|
+
* ones, `McpSdkServerConfig.toolNames`) are never filtered by it -- name only built-ins here. Leaving
|
|
164
|
+
* `ToolSearch` out switches deferral off, as in claude. Opt-in built-ins (`Search`) are advertised only
|
|
165
|
+
* when this list names them. See `RuntimeConfig.tools`.
|
|
166
|
+
*/
|
|
167
|
+
tools?: string[] | {
|
|
168
|
+
type: "preset";
|
|
169
|
+
preset: "claude_code";
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* DISCLOSED WINTER option: tools that start DEFERRED (loaded through `ToolSearch` on first use) while
|
|
173
|
+
* Tool Search is active -- the host's way to defer a BUILT-IN (`CronList`), which otherwise never
|
|
174
|
+
* defers. See `RuntimeConfig.deferTools`.
|
|
175
|
+
*/
|
|
176
|
+
deferTools?: string[];
|
|
177
|
+
/** DISCLOSED WINTER option: a tool's old names, `{ <old>: <current> }`. See `RuntimeConfig.legacyToolNames`. */
|
|
178
|
+
legacyToolNames?: Record<string, string>;
|
|
179
|
+
/** DISCLOSED WINTER option: MCP server names only the host's own in-process servers may use. See `RuntimeConfig.reservedMcpServerNames`. */
|
|
180
|
+
reservedMcpServerNames?: string[];
|
|
158
181
|
allowDangerouslySkipPermissions?: boolean;
|
|
159
182
|
canUseTool?: CanUseTool;
|
|
160
183
|
hooks?: Partial<Record<HookEvent, HookCallbackMatcher[]>>;
|
|
@@ -279,6 +279,28 @@ export interface McpSdkServerConfig {
|
|
|
279
279
|
name: string;
|
|
280
280
|
timeout?: number;
|
|
281
281
|
tools?: WireMcpToolDefinition[];
|
|
282
|
+
/**
|
|
283
|
+
* WINTER-OWNED EXTENSION: advertise some of this in-process server's tools under a HOST-CHOSEN plain
|
|
284
|
+
* name instead of `mcp__<server>__<tool>` -- `{ <tool as listTools() names it>: <plain name> }`.
|
|
285
|
+
*
|
|
286
|
+
* A renamed tool is an ordinary-looking tool to the model (`Browser`, never `mcp__…`) and that ONE name
|
|
287
|
+
* is its identity everywhere a name is carried: the provider request, the transcript, the host's frames,
|
|
288
|
+
* hook inputs' `tool_name`, `canUseTool`, `permission_denials`. Underneath it is still this server's MCP
|
|
289
|
+
* tool: it defers like one (unless `_meta["anthropic/alwaysLoad"]`), the call still arrives at the host
|
|
290
|
+
* as `sdk_mcp_call {server, tool}` with the ORIGINAL tool name, and `winter_mcp_server` / `canUseTool`'s
|
|
291
|
+
* `mcpServer` still name the server. The old `mcp__<server>__<tool>` spelling stays an EQUIVALENT
|
|
292
|
+
* identity: a permission rule (`mcp__<server>__<tool>`, `mcp__<server>__*`), a bare `disallowedTools`
|
|
293
|
+
* entry or a hook matcher written against it governs the renamed tool too (strictest-of, as for an
|
|
294
|
+
* alias) -- and, as for an alias, the call is then evaluated UNDER that spelling: the hook it selected
|
|
295
|
+
* and the prompt its ask rule raised carry `mcp__<server>__<tool>` as `tool_name`. A model call under the
|
|
296
|
+
* old spelling (a resumed history) runs as the renamed tool.
|
|
297
|
+
*
|
|
298
|
+
* A plain name must look like a tool name (`[A-Za-z][A-Za-z0-9_-]*`, at most 64 characters), must not
|
|
299
|
+
* start with `mcp__`, and must not collide with any other registered tool -- a collision refuses the
|
|
300
|
+
* session at startup rather than shadowing a tool. Only an in-process (`sdk`) server may rename; the
|
|
301
|
+
* host owns it.
|
|
302
|
+
*/
|
|
303
|
+
toolNames?: Record<string, string>;
|
|
282
304
|
}
|
|
283
305
|
export type McpServerConfigForProcessTransport = McpStdioServerConfig | McpHttpServerConfig | McpSSEServerConfig | McpSdkServerConfig;
|
|
284
306
|
export type AgentMcpServerSpec = string | Record<string, McpServerConfigForProcessTransport>;
|
|
@@ -389,6 +411,44 @@ export interface RuntimeConfig {
|
|
|
389
411
|
familyMetadata?: {
|
|
390
412
|
taskNative?: boolean;
|
|
391
413
|
};
|
|
414
|
+
/**
|
|
415
|
+
* `Options.tools` (claude's own option): the BUILT-IN tool set this session is offered, by name.
|
|
416
|
+
* Absent = every built-in (claude's `claude_code` preset, which the wrapper serializes as absent).
|
|
417
|
+
* Filters built-ins only -- an MCP server's tools, a host's plain-named in-process tools and
|
|
418
|
+
* host-generated tools (`StructuredOutput`) are never named here and never filtered by it. A built-in
|
|
419
|
+
* left out is not advertised, not in ToolSearch's pool and refused at dispatch as a tool the model
|
|
420
|
+
* was not offered. `ToolSearch` left out switches deferral off (claude's rule: no search tool, no
|
|
421
|
+
* deferred tools). A few built-ins (`Search`) are OPT-IN: advertised only when this list names them.
|
|
422
|
+
*/
|
|
423
|
+
tools?: string[];
|
|
424
|
+
/**
|
|
425
|
+
* Winter extension: tools that START DEFERRED -- loaded through `ToolSearch` on first use -- when Tool
|
|
426
|
+
* Search is active. A built-in otherwise never defers; an MCP tool already does (unless its
|
|
427
|
+
* `_meta["anthropic/alwaysLoad"]`, which still wins). `ToolSearch` itself is never deferred.
|
|
428
|
+
* Inert while deferral is inactive (full injection).
|
|
429
|
+
*/
|
|
430
|
+
deferTools?: string[];
|
|
431
|
+
/**
|
|
432
|
+
* Winter extension: a tool's OLD names -- `{ <old name>: <current tool name> }` -- for a host whose
|
|
433
|
+
* own tool became another one (a host's in-process `mcp__<server>__Search` became the `Search`
|
|
434
|
+
* built-in). The old name keeps working everywhere a name is read: a model call under it (a resumed
|
|
435
|
+
* history taught it) runs the current tool, `ToolSearch`'s `select:` finds it, an agent definition's
|
|
436
|
+
* `tools` list keeps it, a rule, bare `disallowedTools` entry or hook matcher naming it governs the
|
|
437
|
+
* current tool (strictest-of, as for an alias). A plain-named in-process tool's own
|
|
438
|
+
* `mcp__<server>__<tool>` spelling needs no entry here: it is resolved the same way by itself. A key
|
|
439
|
+
* that names a registered tool is ignored (the live tool wins).
|
|
440
|
+
*/
|
|
441
|
+
legacyToolNames?: Record<string, string>;
|
|
442
|
+
/**
|
|
443
|
+
* Winter extension: MCP server NAMES no server may take in this session except the host's own
|
|
444
|
+
* in-process (`type: "sdk"`) servers in `mcpServers` -- whatever its origin: a settings scope, a plugin's
|
|
445
|
+
* `.mcp.json`, an explicit non-sdk entry, the live `mcp_set_servers` door (each refused typed
|
|
446
|
+
* `reserved_name` and never connected), and an agent definition's inline server (connected under a
|
|
447
|
+
* renamed `<name>_<n>`, as for any clash; an inline in-process one under a reserved name is not
|
|
448
|
+
* connected). For a host whose own tools are classified by their server (trust keyed on
|
|
449
|
+
* `mcp__<server>__*`), so no foreign server can wear that spelling.
|
|
450
|
+
*/
|
|
451
|
+
reservedMcpServerNames?: string[];
|
|
392
452
|
mcpServers?: Record<string, McpServerConfigForProcessTransport>;
|
|
393
453
|
strictMcpConfig?: boolean;
|
|
394
454
|
toolAliases?: Record<string, string>;
|
|
@@ -306,6 +306,16 @@ export type WireContentBlock = {
|
|
|
306
306
|
tool_use_id: string;
|
|
307
307
|
content: string | WireContentBlock[];
|
|
308
308
|
is_error?: boolean;
|
|
309
|
+
/**
|
|
310
|
+
* Winter-only, HOST-facing frame only (never model-visible, never in a transcript): the sites a web
|
|
311
|
+
* tool's result names and the icon the tool knows for each -- `WebFetch`'s page icon (the page's
|
|
312
|
+
* own declared `<link rel=icon>`, else its origin's `/favicon.ico`), `WebSearch`'s Exa `favicon`.
|
|
313
|
+
* At most 10 entries; every url https. Absent on every other result.
|
|
314
|
+
*/
|
|
315
|
+
winter_site_icons?: Array<{
|
|
316
|
+
url: string;
|
|
317
|
+
icon_url: string;
|
|
318
|
+
}>;
|
|
309
319
|
[k: string]: unknown;
|
|
310
320
|
} | {
|
|
311
321
|
type: "image";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yanlinglabs/winter-agent-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.38",
|
|
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.
|
|
48
|
+
"@yanlinglabs/winter-provider-catalog": "0.0.38"
|
|
49
49
|
},
|
|
50
50
|
"optionalDependencies": {
|
|
51
|
-
"@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.
|
|
51
|
+
"@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.38"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^26.4.0",
|
|
55
|
-
"@yanlinglabs/winter-
|
|
56
|
-
"@yanlinglabs/winter-
|
|
55
|
+
"@yanlinglabs/winter-agent-runtime": "0.0.38",
|
|
56
|
+
"@yanlinglabs/winter-conformance": "0.0.38"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {}
|
|
59
59
|
}
|