@yanlinglabs/winter-runtime-sdk 0.0.1 → 0.0.2
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 +68 -15
- package/dist/door.d.ts +62 -1
- package/dist/errors.d.ts +8 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.js +376 -298
- package/dist/messaging/index.d.ts +1 -3
- package/dist/messaging/router.d.ts +1 -12
- package/dist/official/aliases.d.ts +6 -2
- package/dist/official/index.d.ts +2 -2
- package/dist/official/mcp-descriptors.d.ts +59 -47
- package/dist/sdk.d.ts +90 -5
- package/dist/version-matrix.d.ts +44 -4
- package/package.json +5 -5
- package/dist/messaging/handlers.d.ts +0 -56
- package/dist/native-args.d.ts +0 -76
|
@@ -2,7 +2,7 @@ export { createRuntimeDirectory } from "../directory/directory.js";
|
|
|
2
2
|
export type { DirectorySnapshot, RuntimeDirectoryHandle, RuntimeDirectoryOptions } from "../directory/directory.js";
|
|
3
3
|
export type { RuntimeDirectoryRecoveryHooks, RuntimeDirectoryRetention } from "../directory/recovery.js";
|
|
4
4
|
export { entryToChildLike, entryToListedRuntimeObject, entryToListedRuntimeObjectList, isListableFrom, isLiveStatus, isResolvableFrom, mergeAdapterOwnedFields, owningSessionIdOf, parentAddressOf, sessionAddressOf } from "../directory/entries.js";
|
|
5
|
-
export { createGlobalMessaging,
|
|
5
|
+
export { createGlobalMessaging, deriveMessageId } from "./router.js";
|
|
6
6
|
export type { GlobalMessagingContext, GlobalMessagingHandle, GlobalMessagingOptions, ReplyRequest } from "./router.js";
|
|
7
7
|
export { createWinterMessagingAdapter } from "./winter-adapter.js";
|
|
8
8
|
export type { WinterMessagingAdapter, WinterMessagingAdapterDeps } from "./winter-adapter.js";
|
|
@@ -15,8 +15,6 @@ export type { InboundPolicy, InboundPolicyDeps, InboundPolicyHooks, InboundVerdi
|
|
|
15
15
|
export { createAttachedSessionRegistry } from "./sessions.js";
|
|
16
16
|
export type { AttachedOfficialSession, AttachedSession, AttachedSessionRegistry, AttachedWinterSession, LiveSessionStatus } from "./sessions.js";
|
|
17
17
|
export { renderAttributedTurn, renderOwnerQualifiedTurn, UnattributableSenderError } from "./attribution.js";
|
|
18
|
-
export { createMessagingToolHandlers, toolUseIdFromExtra, VENDOR_TOOL_USE_ID_META_KEY } from "./handlers.js";
|
|
19
|
-
export type { MessagingToolCaller, MessagingToolHandler, MessagingToolHandlers, MessagingToolResult } from "./handlers.js";
|
|
20
18
|
import { type RuntimeDirectoryHandle, type RuntimeDirectoryOptions } from "../directory/directory.js";
|
|
21
19
|
import type { SeamContext } from "../seams/context.js";
|
|
22
20
|
import { type GlobalMessagingHandle, type GlobalMessagingOptions } from "./router.js";
|
|
@@ -2,7 +2,7 @@ import type { NotificationRecord, SendMessageResult } from "@yanlinglabs/winter-
|
|
|
2
2
|
import type { RuntimeDirectoryHandle } from "../directory/directory.js";
|
|
3
3
|
import type { SeamContext } from "../seams/context.js";
|
|
4
4
|
import type { GlobalMessaging, SendMessageRequest } from "../seams/global-messaging.js";
|
|
5
|
-
import type { DeliveryOutcome, GlobalAgentMessage,
|
|
5
|
+
import type { DeliveryOutcome, GlobalAgentMessage, SerializedRuntimeAddress } from "../seams/messaging-contract.js";
|
|
6
6
|
import { type InboundPolicyHooks } from "./inbound.js";
|
|
7
7
|
import { type OfficialMessagingAdapter, type OfficialMessagingAdapterDeps } from "./official-adapter.js";
|
|
8
8
|
import { type AttachedOfficialSession, type AttachedWinterSession } from "./sessions.js";
|
|
@@ -88,14 +88,3 @@ export interface GlobalMessagingHandle extends GlobalMessaging {
|
|
|
88
88
|
*/
|
|
89
89
|
export declare function deriveMessageId(senderSessionId: string, toolUseId: string): string;
|
|
90
90
|
export declare function createGlobalMessaging(context: GlobalMessagingContext, options?: GlobalMessagingOptions): GlobalMessagingHandle;
|
|
91
|
-
/**
|
|
92
|
-
* The canonical address a `SendMessage`/`ListAgents` handler runs AS (see `handlers.ts`).
|
|
93
|
-
*
|
|
94
|
-
* The subpath's own `callerAddress` builds `agent:<parent>:<child>` for a child caller and
|
|
95
|
-
* `session:<id>` for a top-level one — the same rule the resolution fence reads, so the handler and
|
|
96
|
-
* the router can never disagree about who is asking.
|
|
97
|
-
*/
|
|
98
|
-
export declare function callerAddressOf(caller: {
|
|
99
|
-
sessionId: string;
|
|
100
|
-
agentId?: string;
|
|
101
|
-
}): RuntimeAddress;
|
|
@@ -6,14 +6,18 @@ export declare const ALIASED_BUILTINS: readonly [{
|
|
|
6
6
|
}, {
|
|
7
7
|
readonly builtin: "ListAgents";
|
|
8
8
|
readonly tool: "list_agents";
|
|
9
|
+
}, {
|
|
10
|
+
readonly builtin: "ReadNotifications";
|
|
11
|
+
readonly tool: "read_notifications";
|
|
12
|
+
}, {
|
|
13
|
+
readonly builtin: "advisor";
|
|
14
|
+
readonly tool: "advisor";
|
|
9
15
|
}];
|
|
10
16
|
export type AliasedBuiltin = (typeof ALIASED_BUILTINS)[number]["builtin"];
|
|
11
17
|
/** §2's `toolAliases` value: `{ SendMessage: "mcp__<server>__send_message", … }`. */
|
|
12
18
|
export declare function officialToolAliases(brand: Pick<BrandProfile, "mcpServerName">): Record<string, string>;
|
|
13
19
|
/** The canonical name one aliased built-in resolves to (single hop — never a chain). */
|
|
14
20
|
export declare function aliasTargetFor(builtin: AliasedBuiltin, brand: Pick<BrandProfile, "mcpServerName">): string;
|
|
15
|
-
export { LIST_AGENTS_FIELD_MAX, NATIVE_LIST_AGENTS_OUTPUT_SCHEMA, NATIVE_LIST_AGENTS_SCHEMA, NATIVE_SEND_MESSAGE_SCHEMA, SEND_MESSAGE_SUMMARY_MAX, SEND_MESSAGE_TO_MAX, acceptNativeListAgentsArgs, acceptNativeSendMessageArgs, } from "../native-args.js";
|
|
16
|
-
export type { NativeArgsResult, NativeListAgentsArgs, NativeSendMessageArgs } from "../native-args.js";
|
|
17
21
|
/**
|
|
18
22
|
* How the canonical duplicates are exposed (§7's "SHOULD be deferred/hidden").
|
|
19
23
|
*
|
package/dist/official/index.d.ts
CHANGED
|
@@ -17,8 +17,8 @@ export { EXECUTION_INDIRECTION_ENV_NAMES, EXECUTION_INDIRECTION_ENV_PREFIXES, is
|
|
|
17
17
|
export type { EnvAllowlistSnapshot, OfficialEnvInput, OfficialEnvPolicy } from "./env-allowlist.js";
|
|
18
18
|
export { OFFICIAL_ERROR_CODES, OfficialStdoutUnterminatedError, OfficialAgentResultError, OfficialApiError, OfficialBranchError, OfficialConfigurationError, OfficialConnectionError, OfficialExecutableNotFoundError, OfficialInterruptedError, OfficialInvalidResumeError, OfficialKilledError, OfficialMcpError, OfficialNonzeroExitError, OfficialPermissionDeniedError, OfficialProtocolError, OfficialSessionNotFoundError, OfficialSessionStoreError, OfficialToolError, isOfficialBranchError, } from "./errors.js";
|
|
19
19
|
export type { OfficialCrashClass, OfficialErrorCode, WinterErrorClassName } from "./errors.js";
|
|
20
|
-
export { OFFICIAL_MATERIALIZATION_DROPS,
|
|
21
|
-
export type { InputShapeFactory, JsonSchemaObject,
|
|
20
|
+
export { OFFICIAL_MATERIALIZATION_DROPS, canonicalToolNames, materializeOfficialMcpServer, officialMcpServers, winterMcpServerDescriptor } from "./mcp-descriptors.js";
|
|
21
|
+
export type { InputShapeFactory, JsonSchemaObject, OfficialMcpModule, WinterMcpHandler, WinterMcpServerDescriptor, WinterMcpToolDescriptor, WinterMcpToolResult } from "./mcp-descriptors.js";
|
|
22
22
|
export { AUTO_MEMORY_LOAD_CAP, DEFAULT_EXCLUDE_DYNAMIC_SECTIONS, PINNED_SYSTEM_PROMPT_PRESET, assertOptionsInvariants, brandedFlagSettings, buildOfficialOptions, captureOptions, mergeHooks } from "./options-template.js";
|
|
23
23
|
export type { OptionsTemplatePolicy } from "./options-template.js";
|
|
24
24
|
export { SPOOL_SEGMENTS, classifyLocalWriteRoot, officialSpoolRoot, validateObservedConfigDir, vendorTempRootReport } from "./spool.js";
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { type BrandProfile } from "@yanlinglabs/winter-agent-sdk";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { type BrandProfile, type McpSdkServerConfigWithInstance } from "@yanlinglabs/winter-agent-sdk";
|
|
2
|
+
import { type AdvisorToolDeps, type JsonSchemaObject, type MessagingToolPort, type WinterToolCaller } from "@yanlinglabs/winter-agent-sdk/tools";
|
|
3
|
+
import { RuntimeLaunchInputError } from "../errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* ONE `JsonSchemaObject`, AND IT IS THE SDK'S (interim review I-3).
|
|
6
|
+
*
|
|
7
|
+
* The router used to declare its own — `properties` required, no `additionalProperties` — and every
|
|
8
|
+
* composition of an SDK schema into a descriptor went through `as unknown as JsonSchemaObject`. Two
|
|
9
|
+
* types for one contract is how the two copies of the native schemas drifted in the first place
|
|
10
|
+
* (barrel-exports.test.ts's own header), so the type travels with the definitions it describes.
|
|
11
|
+
*/
|
|
12
|
+
export type { JsonSchemaObject };
|
|
8
13
|
/** What a handler answers with — the MCP content shape, identical on both branches. */
|
|
9
14
|
export interface WinterMcpToolResult {
|
|
10
15
|
content: Array<{
|
|
@@ -16,20 +21,20 @@ export interface WinterMcpToolResult {
|
|
|
16
21
|
/**
|
|
17
22
|
* A tool handler, and the vendor's own second argument (item 15).
|
|
18
23
|
*
|
|
19
|
-
* `extra` IS FORWARDED, NOT DROPPED
|
|
20
|
-
*
|
|
21
|
-
* key
|
|
22
|
-
*
|
|
23
|
-
* the MCP REQUEST CONTEXT — the JSON-RPC request id and `_meta` — which is not the model's
|
|
24
|
-
* `tool_use_id`. `test/official/runtime-aliases.test.ts` records what the pinned runtime actually
|
|
25
|
-
* puts there; see that test and this module's own note below for the answer.
|
|
26
|
-
*
|
|
27
|
-
* Forwarding it is worth doing either way: it is the only channel the vendor gives a tool for request
|
|
28
|
-
* context, dropping it is unrecoverable at the handler, and a handler that does not want it simply
|
|
29
|
-
* declares one parameter.
|
|
24
|
+
* `extra` IS FORWARDED, NOT DROPPED, and what it carries is measured rather than assumed: on 0.3.250
|
|
25
|
+
* `extra._meta["claudecode/toolUseId"]` is the id the model emitted, which is the half of WS-10 §12's
|
|
26
|
+
* retry key the official branch could not otherwise have. The SDK's `toolUseIdFromExtra` reads it (and
|
|
27
|
+
* falls back to the bound caller's id), so the router forwards the argument and decides nothing.
|
|
30
28
|
*/
|
|
31
29
|
export type WinterMcpHandler = (args: unknown, extra?: unknown) => Promise<WinterMcpToolResult>;
|
|
32
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* One tool on the standing server — the ROUTER'S OWN COMPOSITION TYPE, and nothing more (R-8-1).
|
|
32
|
+
*
|
|
33
|
+
* It is a `WinterToolDefinition` (the SDK's: bare name, description, schemas, annotations, permission
|
|
34
|
+
* class) plus the two things only a HOST can supply: the handler that runs it and how this branch
|
|
35
|
+
* exposes it. The router declares no tool of its own — every field but those two is read off the
|
|
36
|
+
* definition the SDK owns.
|
|
37
|
+
*/
|
|
33
38
|
export interface WinterMcpToolDescriptor {
|
|
34
39
|
/** The bare tool name (`send_message`); the canonical name is derived from it and the brand. */
|
|
35
40
|
tool: string;
|
|
@@ -49,43 +54,51 @@ export interface WinterMcpServerDescriptor {
|
|
|
49
54
|
version: string;
|
|
50
55
|
tools: readonly WinterMcpToolDescriptor[];
|
|
51
56
|
}
|
|
52
|
-
/** The two messaging handlers §7's aliases resolve to. Their implementations are the router's. */
|
|
53
|
-
export interface MessagingHandlers {
|
|
54
|
-
sendMessage: WinterMcpHandler;
|
|
55
|
-
listAgents: WinterMcpHandler;
|
|
56
|
-
}
|
|
57
57
|
/**
|
|
58
|
-
*
|
|
59
|
-
* argument schemas exactly").
|
|
58
|
+
* THE STANDING SERVER, COMPOSED FROM THE SDK'S DEFINITIONS AND THE SDK'S HANDLER FACTORIES (R-8-1).
|
|
60
59
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
*
|
|
60
|
+
* THE ROUTER OWNS NO TOOL. It used to declare `send_message` and `list_agents` here — their
|
|
61
|
+
* descriptions, their native schemas, their acceptors — beside a second copy of the same declarations
|
|
62
|
+
* inside the Winter runtime, and the two had already drifted on what `to` may contain and on what an
|
|
63
|
+
* over-long `summary` does. `@yanlinglabs/winter-agent-sdk/tools` is now the single declaration, and
|
|
64
|
+
* this function is what BINDS it: `WINTER_DEFAULT_TOOL_DEFINITIONS` × the SDK's handler factories,
|
|
65
|
+
* under the brand's server name.
|
|
67
66
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*/
|
|
73
|
-
export declare function assertNoAdvisor(tools: readonly WinterMcpToolDescriptor[], branchLabel: string): void;
|
|
74
|
-
/**
|
|
75
|
-
* Builds the standing server descriptor for a session.
|
|
67
|
+
* THE PORT IS PASSED STRAIGHT THROUGH (ruling P-3). `GlobalMessagingHandle` satisfies
|
|
68
|
+
* `MessagingToolPort` structurally — `sendDetailed`, `listReachable({from})`, `readNotifications(id)`
|
|
69
|
+
* — so the router needs no adapter of its own and `messagingToolPortFromRuntimeDeps` (which adapts the
|
|
70
|
+
* RUNTIME's deps) is never used here.
|
|
76
71
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
72
|
+
* THE ADVISOR IS ALWAYS REGISTERED (interim review I-5). The Winter runtime always advertises
|
|
73
|
+
* `advisor`; gating the official branch's copy on a host option would make the two legs' advertised
|
|
74
|
+
* sets differ by a setting that changes nothing on the other leg. `advisor.resolveReviewer` supplies
|
|
75
|
+
* the reviewer — its default answers `undefined`, which is WS-06 §4's ordinary tool error, not a throw.
|
|
81
76
|
*/
|
|
82
77
|
export declare function winterMcpServerDescriptor(args: {
|
|
83
78
|
brand: Pick<BrandProfile, "mcpServerName">;
|
|
84
|
-
|
|
79
|
+
port: MessagingToolPort;
|
|
80
|
+
caller: WinterToolCaller | (() => WinterToolCaller);
|
|
81
|
+
advisor: Omit<AdvisorToolDeps, "resolveReviewer"> & Partial<Pick<AdvisorToolDeps, "resolveReviewer">>;
|
|
85
82
|
capabilities?: readonly WinterMcpToolDescriptor[];
|
|
86
83
|
version?: string;
|
|
87
|
-
branchLabel: string;
|
|
88
84
|
}): WinterMcpServerDescriptor;
|
|
85
|
+
/** One capability server, as a descriptor the official branch can register. */
|
|
86
|
+
export declare function capabilityServerDescriptor(server: McpSdkServerConfigWithInstance, version?: string): WinterMcpServerDescriptor;
|
|
87
|
+
/**
|
|
88
|
+
* The ONE refusal both legs raise when a caller's own `mcpServers` key names a forwarded capability.
|
|
89
|
+
*
|
|
90
|
+
* IT IS SHARED BECAUSE THE TWO LEGS MUST SAY THE SAME THING (review r1). The Winter leg refuses in
|
|
91
|
+
* `forwardableOptions`, the official leg before its launch; the same mistake producing a typed error
|
|
92
|
+
* on one leg and a silent per-key override on the other would leave the two branches advertising
|
|
93
|
+
* different tools under one name, with nothing to read about it. Two copies of this sentence is how
|
|
94
|
+
* that starts being true again, so there is one.
|
|
95
|
+
*/
|
|
96
|
+
export declare function capabilityNameCollisionError(args: {
|
|
97
|
+
field: string;
|
|
98
|
+
name: string;
|
|
99
|
+
}): RuntimeLaunchInputError;
|
|
100
|
+
/** Every capability server, in the order the host declared them. */
|
|
101
|
+
export declare function capabilityServerDescriptors(servers: readonly McpSdkServerConfigWithInstance[]): readonly WinterMcpServerDescriptor[];
|
|
89
102
|
/** The canonical names a descriptor registers — the identity both branches must agree on. */
|
|
90
103
|
export declare function canonicalToolNames(descriptor: WinterMcpServerDescriptor, brand: Pick<BrandProfile, "mcpServerName">): readonly string[];
|
|
91
104
|
/** The subset of the injected official module this needs. Duck-typed: the seam declares only `query`. */
|
|
@@ -119,7 +132,6 @@ export declare function materializeOfficialMcpServer(args: {
|
|
|
119
132
|
toInputShape: InputShapeFactory;
|
|
120
133
|
branchLabel: string;
|
|
121
134
|
}): unknown;
|
|
122
|
-
/** `Options.mcpServers` for this branch: one entry, keyed by the brand's own server name. */
|
|
123
135
|
/** The descriptor fields the official branch's registration cannot carry (review r1, n3). */
|
|
124
136
|
export declare const OFFICIAL_MATERIALIZATION_DROPS: readonly string[];
|
|
125
137
|
export declare function officialMcpServers(args: {
|
package/dist/sdk.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BrandProfile, Options, Query, SessionKey } from "@yanlinglabs/winter-agent-sdk";
|
|
1
|
+
import type { BrandProfile, McpSdkServerConfigWithInstance, Options, Query, SessionKey } from "@yanlinglabs/winter-agent-sdk";
|
|
2
2
|
import { type RouterOfficialInput, type RouterOfficialPolicy, type RouterQuery } from "./door.js";
|
|
3
3
|
import type { SeamContextWithDirectory } from "./seams/context.js";
|
|
4
4
|
import type { OfficialSdkModule } from "./seams/official-sdk-shapes.js";
|
|
@@ -11,6 +11,8 @@ import type { RuntimeDirectory } from "./seams/directory.js";
|
|
|
11
11
|
import type { RuntimeDirectoryStore } from "./seams/directory-store.js";
|
|
12
12
|
import type { GlobalMessagingOptions, RuntimeDirectoryOptions } from "./messaging/index.js";
|
|
13
13
|
import type { HandoffBarrierDeps } from "./store/index.js";
|
|
14
|
+
import type { ReviewerResolver } from "@yanlinglabs/winter-agent-sdk/tools";
|
|
15
|
+
import { type InputShapeFactory } from "./official/mcp-descriptors.js";
|
|
14
16
|
import type { RuntimeKind, RuntimeSelection, SelectionInput } from "./selection/runtime-selection.js";
|
|
15
17
|
import { type VersionMatrixReport } from "./version-matrix.js";
|
|
16
18
|
/**
|
|
@@ -38,6 +40,21 @@ export interface RuntimeSdkPeers {
|
|
|
38
40
|
}
|
|
39
41
|
export interface RuntimeSdkOptions {
|
|
40
42
|
peers: RuntimeSdkPeers;
|
|
43
|
+
/**
|
|
44
|
+
* Host-declared peer package versions (D19a/R2, WS-02 §7.1) — THE ONLY DOOR inside a compiled
|
|
45
|
+
* binary. The version matrix's probe 2 (`resolved-manifest`) resolves a peer's `package.json` via
|
|
46
|
+
* `createRequire(...).resolve()`, which cannot see outside a compiled binary's own bundle
|
|
47
|
+
* (`file:///$bunfs/...`); a host that self-spawns its own compiled artifact and whose injected peer
|
|
48
|
+
* exports no version identity of its own (probe 1) has NOTHING for the matrix to read unless it
|
|
49
|
+
* declares one here, from its own vendored `VERSIONS.json`. Declaring a version wins over both
|
|
50
|
+
* probes when it parses — it does not bypass the matrix's range/exact-pin checks, only replaces how
|
|
51
|
+
* the identity was DISCOVERED; an unparseable declared value falls through to probe 1 rather than
|
|
52
|
+
* refusing on its own. Absent, behaviour is unchanged: probes 1 and 2, in that order.
|
|
53
|
+
*/
|
|
54
|
+
peerVersions?: {
|
|
55
|
+
winterAgentSdk?: string;
|
|
56
|
+
claudeAgentSdk?: string;
|
|
57
|
+
};
|
|
41
58
|
/** R-7b-2's seam; default = in-memory (which is also what every hermetic test uses). */
|
|
42
59
|
directoryStore?: RuntimeDirectoryStore;
|
|
43
60
|
/** Host-provided credential reads (WS-14 §12) — never disk, never this package's own keychain. */
|
|
@@ -57,6 +74,61 @@ export interface RuntimeSdkOptions {
|
|
|
57
74
|
* fill in when neither does.
|
|
58
75
|
*/
|
|
59
76
|
brand?: Partial<BrandProfile>;
|
|
77
|
+
/**
|
|
78
|
+
* WS-09 §1.3's capability servers, as the Winter SDK's own in-process shape — FORWARDED ON BOTH
|
|
79
|
+
* LEGS, never rewritten into anything else (R-8, and the user's tool-ownership ruling R-8-1).
|
|
80
|
+
*
|
|
81
|
+
* THE ROUTER OWNS NO TOOL. The daemon owns the capability tools — computer, browser, office — and
|
|
82
|
+
* hands them over as MCP SERVERS; this is the door they come through, and the router's whole job is
|
|
83
|
+
* to put the same servers in front of both runtimes. The Winter leg receives each entry BY
|
|
84
|
+
* REFERENCE under its own `name`, merged into `Options.mcpServers`. The official leg cannot take the
|
|
85
|
+
* object itself (its runtime registers in-process servers through its own constructor, over its own
|
|
86
|
+
* validator's schema shape), so the same tools are REGISTERED there from the server's own
|
|
87
|
+
* declaration — see `capabilityServerDescriptor`. Identical names, identical schemas, identical
|
|
88
|
+
* handlers, two registrations.
|
|
89
|
+
*
|
|
90
|
+
* THE BRAND'S OWN SERVER NAME IS RESERVED. `brand.mcpServerName` is the standing server's key on the
|
|
91
|
+
* official branch (§7's aliases resolve to `mcp__<mcpServerName>__<tool>`), so a capability server
|
|
92
|
+
* that claimed it would shadow the messaging tools on one branch and not the other. That is a typed
|
|
93
|
+
* refusal at construction, not a silent overwrite.
|
|
94
|
+
*
|
|
95
|
+
* WITHOUT `toInputShape` THIS IS A WINTER-LEG-ONLY DOOR: the official leg refuses rather than open a
|
|
96
|
+
* session whose capability tools exist on one branch only.
|
|
97
|
+
*
|
|
98
|
+
* A CALLER'S OWN `Options.mcpServers` REACHES THE WINTER LEG ONLY, and always has: the official leg
|
|
99
|
+
* builds its servers from this constructor and `runtime.official.mcpServers`, and never reads the
|
|
100
|
+
* pinned `Options` field at all. A caller key that collides with a capability name is therefore
|
|
101
|
+
* refused for BOTH legs at the door (interim review I-6) rather than refused on one and silently
|
|
102
|
+
* dropped on the other.
|
|
103
|
+
*/
|
|
104
|
+
capabilities?: readonly McpSdkServerConfigWithInstance[];
|
|
105
|
+
/**
|
|
106
|
+
* The host's JSON-Schema → validator-shape bridge, for the official branch's in-process servers.
|
|
107
|
+
*
|
|
108
|
+
* INJECTED BECAUSE THE ROUTER DEPENDS ON NO VALIDATOR (see `official/mcp-descriptors.ts`'s header):
|
|
109
|
+
* the official runtime's own server constructor takes schemas in its peer validator's shape, and a
|
|
110
|
+
* package whose entire design is "two injected peers and nothing else" will not grow a third
|
|
111
|
+
* dependency to produce them. A host that has the official SDK already has that validator, and
|
|
112
|
+
* writes this in one line.
|
|
113
|
+
*/
|
|
114
|
+
toInputShape?: InputShapeFactory;
|
|
115
|
+
/**
|
|
116
|
+
* The REVIEWER behind the standing advisor (R-8-1(3), ruling P-6; interim review I-5).
|
|
117
|
+
*
|
|
118
|
+
* The advisor tool itself is not optional and is not configured here: the official leg registers it
|
|
119
|
+
* on the standing server unconditionally, because the Winter runtime always advertises `advisor` and
|
|
120
|
+
* two legs whose advertised sets differ by a host option is the divergence WS-14 §11 exists to
|
|
121
|
+
* prevent. This supplies WHO REVIEWS — a resolver the host owns, because reviewer RESOLUTION is the
|
|
122
|
+
* runtime's provider-layer concern (D30) and the router has no provider layer. With no resolver the
|
|
123
|
+
* tool answers WS-06 §4's ordinary error.
|
|
124
|
+
*
|
|
125
|
+
* The transcript is NOT a field here: the source is this session's own, built by the leg over the one
|
|
126
|
+
* shared store, keyed by the backend session id the runtime reports at `system/init`.
|
|
127
|
+
*/
|
|
128
|
+
advisor?: {
|
|
129
|
+
resolveReviewer: ReviewerResolver;
|
|
130
|
+
maxChars?: number;
|
|
131
|
+
};
|
|
60
132
|
/**
|
|
61
133
|
* The handoff barrier's collaborators (whole-branch review, F-3).
|
|
62
134
|
*
|
|
@@ -197,14 +269,27 @@ export declare function runtimeSdkInternals(sdk: RuntimeSdk): RuntimeSdkInternal
|
|
|
197
269
|
/**
|
|
198
270
|
* Builds the object forwarded to a peer's `query()`.
|
|
199
271
|
*
|
|
272
|
+
* THE INVARIANT, IN ONE SENTENCE: **the forwarded options are the caller's options minus
|
|
273
|
+
* `ROUTER_ONLY_OPTION_KEYS`, plus the brand's capability-server entries under `mcpServers`, and
|
|
274
|
+
* nothing else is rewritten.**
|
|
275
|
+
*
|
|
200
276
|
* THE COMMON CASE FORWARDS THE CALLER'S OWN OBJECT, by reference. "Passes through verbatim" is a
|
|
201
277
|
* property a test can only really check by identity, and a router that copied unconditionally would
|
|
202
278
|
* be quietly deciding which of `Options`' members it knows about — the exact drift D19b's "never a
|
|
203
|
-
* translation layer" rules out. A copy is made ONLY when
|
|
204
|
-
*
|
|
205
|
-
* identity through the copy.
|
|
279
|
+
* translation layer" rules out. A copy is made ONLY when there is something to remove or something to
|
|
280
|
+
* add, because that is the only time the caller's own object would be the wrong thing to hand over;
|
|
281
|
+
* every other member keeps its own value identity through the copy.
|
|
282
|
+
*
|
|
283
|
+
* SO R-8 DID NOT WEAKEN THE PROPERTY, IT RESTATED IT. A host that configures no capabilities is
|
|
284
|
+
* unaffected — the identity return below still fires, and the test that pins it is unchanged. A host
|
|
285
|
+
* that configures them gets a copy whose every member except `mcpServers` is `Object.is`-identical to
|
|
286
|
+
* its own, and whose `mcpServers` is its own entries plus the capability entries, by reference.
|
|
287
|
+
*
|
|
288
|
+
* A CAPABILITY KEY THE CALLER ALSO USES IS A TYPED REFUSAL, never a silent overwrite in either
|
|
289
|
+
* direction: one of the two servers would simply not be there, and the party who would find out is
|
|
290
|
+
* the model, at the one moment the tool matters.
|
|
206
291
|
*/
|
|
207
|
-
export declare function forwardableOptions(options: RouterOptions, brand?: Partial<BrandProfile
|
|
292
|
+
export declare function forwardableOptions(options: RouterOptions, brand?: Partial<BrandProfile>, capabilityServers?: Readonly<Record<string, unknown>>): Options;
|
|
208
293
|
/**
|
|
209
294
|
* Constructs the router. Throws `RuntimeSdkVersionError` on a version-matrix miss (D19a).
|
|
210
295
|
*
|
package/dist/version-matrix.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { RuntimeSdkPeers } from "./sdk.js";
|
|
|
8
8
|
* not a range that quietly widens.
|
|
9
9
|
*/
|
|
10
10
|
export declare const SUPPORTED: {
|
|
11
|
-
readonly winterAgentSdk: ">=0.0.
|
|
11
|
+
readonly winterAgentSdk: ">=0.0.3 <0.1.0";
|
|
12
12
|
readonly claudeAgentSdk: "0.3.250";
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
@@ -18,7 +18,7 @@ export declare const SUPPORTED: {
|
|
|
18
18
|
*/
|
|
19
19
|
export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly ["1.0"];
|
|
20
20
|
/** Where a peer's package version came from. See this module's header. */
|
|
21
|
-
export type PeerVersionSource = "peer-export" | "resolved-manifest";
|
|
21
|
+
export type PeerVersionSource = "host-declared" | "peer-export" | "resolved-manifest";
|
|
22
22
|
export interface PeerVersionIdentity {
|
|
23
23
|
/** The package name the identity was read for. */
|
|
24
24
|
packageName: string;
|
|
@@ -70,8 +70,23 @@ export declare function readExportedVersion(namespace: unknown): string | undefi
|
|
|
70
70
|
* own manifest as a subpath. Every failure mode — no such package, a manifest that will not parse, a
|
|
71
71
|
* manifest with no `version` — returns `undefined`, which the caller turns into the loud refusal.
|
|
72
72
|
* Never throws: a missing OPTIONAL peer must not crash the matrix on its way to reporting itself.
|
|
73
|
+
*
|
|
74
|
+
* `resolveEntry` is an injectable seam (R2), defaulting to the real
|
|
75
|
+
* `createRequire(import.meta.url).resolve` — NOT deleted, still the only resolver this package ever
|
|
76
|
+
* uses on its own. It exists so a test can simulate the one condition this package cannot otherwise
|
|
77
|
+
* reproduce on demand: a compiled binary, where that resolve call cannot see outside the bundle
|
|
78
|
+
* (`file:///$bunfs/...`) and always throws. Production code never passes a second argument.
|
|
79
|
+
*/
|
|
80
|
+
export declare function readResolvedManifestVersion(packageName: string, resolveEntry?: (name: string) => string): string | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* The seams `resolveVersionMatrix` accepts. `resolveEntry`, when given, REPLACES probe 2's resolver
|
|
83
|
+
* end to end (through `identityFor` into `readResolvedManifestVersion`) — the only way a test can make
|
|
84
|
+
* that probe genuinely fail rather than merely be irrelevant because `declared` or peer-export already
|
|
85
|
+
* answered. Production code (`assertVersionMatrix`) never supplies one.
|
|
73
86
|
*/
|
|
74
|
-
export
|
|
87
|
+
export interface VersionMatrixSeams {
|
|
88
|
+
resolveEntry?: (name: string) => string;
|
|
89
|
+
}
|
|
75
90
|
/**
|
|
76
91
|
* Reads each injected peer's version identity and refuses loudly on a miss.
|
|
77
92
|
*
|
|
@@ -79,6 +94,31 @@ export declare function readResolvedManifestVersion(packageName: string): string
|
|
|
79
94
|
* Winter-only host injects `{ winter }` and never loads the official runtime (that is the whole
|
|
80
95
|
* point of the optional peer), so "no claude peer" is a valid, fully-supported configuration and the
|
|
81
96
|
* report simply omits the row.
|
|
97
|
+
*
|
|
98
|
+
* `declared` is `RuntimeSdkOptions.peerVersions` (R2), optional — the one-arg call
|
|
99
|
+
* (`assertVersionMatrix(peers)`) stays legal and behaves exactly as before: with nothing declared,
|
|
100
|
+
* every peer's identity comes from probe 1 or probe 2, unchanged.
|
|
101
|
+
*
|
|
102
|
+
* `seams` is test-only (R2 review r1): NOT exposed here — `resolveVersionMatrix` below is where a test
|
|
103
|
+
* reaches it. A public seam parameter on this function is a production call site that could pass a
|
|
104
|
+
* broken resolver by accident, for a capability real hosts never need.
|
|
105
|
+
*/
|
|
106
|
+
export declare function assertVersionMatrix(peers: RuntimeSdkPeers, declared?: {
|
|
107
|
+
winterAgentSdk?: string;
|
|
108
|
+
claudeAgentSdk?: string;
|
|
109
|
+
}): VersionMatrixReport;
|
|
110
|
+
/**
|
|
111
|
+
* `assertVersionMatrix`'s full implementation, with an injectable `seams` (R2 review r1, `test/spine/
|
|
112
|
+
* version-matrix.test.ts`'s test (d)). NOT on the package barrel (`src/index.ts`) — deliberately: a
|
|
113
|
+
* real host has no reason to override how this package resolves ITS OWN peers' manifests, so this
|
|
114
|
+
* function exists only so a test can force probe 2 (`resolved-manifest`) to GENUINELY fail — the one
|
|
115
|
+
* condition a test cannot otherwise reproduce on demand (in an ordinary dev checkout the real peers
|
|
116
|
+
* really are resolvable, so a test that never overrides the resolver cannot tell "declared won" from
|
|
117
|
+
* "resolved-manifest would have answered the same value anyway"). `assertVersionMatrix` is the public,
|
|
118
|
+
* one-line delegation with the real (default) seams.
|
|
82
119
|
*/
|
|
83
|
-
export declare function
|
|
120
|
+
export declare function resolveVersionMatrix(peers: RuntimeSdkPeers, declared?: {
|
|
121
|
+
winterAgentSdk?: string;
|
|
122
|
+
claudeAgentSdk?: string;
|
|
123
|
+
}, seams?: VersionMatrixSeams): VersionMatrixReport;
|
|
84
124
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yanlinglabs/winter-runtime-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "One door over the Winter Agent SDK and the official Claude Agent SDK: runtime selection, the official-SDK adapter, the shared session store, the handoff barrier and the cross-runtime messaging router.",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@anthropic-ai/claude-agent-sdk": "0.3.250",
|
|
42
|
-
"@yanlinglabs/winter-agent-sdk": ">=0.0.
|
|
42
|
+
"@yanlinglabs/winter-agent-sdk": ">=0.0.3 <0.1.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependenciesMeta": {
|
|
45
45
|
"@anthropic-ai/claude-agent-sdk": {
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"@anthropic-ai/claude-agent-sdk": "0.3.250",
|
|
51
51
|
"@types/bun": "^1.3.0",
|
|
52
52
|
"@types/node": "^26.4.0",
|
|
53
|
-
"@yanlinglabs/winter-agent-sdk": "^0.0.
|
|
54
|
-
"@yanlinglabs/winter-conformance": "^0.0.
|
|
55
|
-
"@yanlinglabs/winter-provider-conformance": "^0.0.
|
|
53
|
+
"@yanlinglabs/winter-agent-sdk": "^0.0.3",
|
|
54
|
+
"@yanlinglabs/winter-conformance": "^0.0.3",
|
|
55
|
+
"@yanlinglabs/winter-provider-conformance": "^0.0.3",
|
|
56
56
|
"typescript": "^5.9.0"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { type GlobalMessagingHandle } from "./router.js";
|
|
2
|
-
/** The MCP result shape both branches return — structurally the descriptor's own (WS-14 §11). */
|
|
3
|
-
export interface MessagingToolResult {
|
|
4
|
-
content: Array<{
|
|
5
|
-
type: "text";
|
|
6
|
-
text: string;
|
|
7
|
-
}>;
|
|
8
|
-
isError?: boolean;
|
|
9
|
-
}
|
|
10
|
-
export type MessagingToolHandler = (args: unknown, extra?: unknown) => Promise<MessagingToolResult>;
|
|
11
|
-
/**
|
|
12
|
-
* WS-10 §12's RETRY KEY, on the official branch — and it exists, which was not known until it was
|
|
13
|
-
* measured (item 15; `test/official/runtime-aliases.test.ts` is the measurement).
|
|
14
|
-
*
|
|
15
|
-
* §12 wants a message id derived from (sender session, TOOL-CALL id) so "a retry allocates the SAME
|
|
16
|
-
* id" and returns the stored outcome instead of starting a second turn. On the Winter branch the
|
|
17
|
-
* caller binds `toolUseId` at registration. On the official branch the handler is inside the vendor's
|
|
18
|
-
* in-process MCP server, where the only per-call channel is the second argument the vendor passes —
|
|
19
|
-
* and the reasonable expectation was that it carries MCP request context (a JSON-RPC request id,
|
|
20
|
-
* `_meta`) rather than an Anthropic-API `tool_use_id`, which is one layer up.
|
|
21
|
-
*
|
|
22
|
-
* THE PINNED RUNTIME BRIDGES THEM. Measured on 0.3.250: `extra._meta["claudecode/toolUseId"]` is the
|
|
23
|
-
* exact id the model emitted. So the official branch gets a real §12 key rather than depending on the
|
|
24
|
-
* rapid-repeat guard, and the vendor's own namespaced `_meta` name is read rather than guessed at.
|
|
25
|
-
*
|
|
26
|
-
* A VENDOR-NAMESPACED KEY IS NEVER REBRANDED (WS-01 §5): `claudecode/toolUseId` is the vendor's name
|
|
27
|
-
* for the vendor's field, exactly like `CLAUDE_CONFIG_DIR`. It is read defensively — an absent or
|
|
28
|
-
* non-string value simply falls back to the bound caller's id — because a future pin may move it, and
|
|
29
|
-
* losing the key must degrade to today's behaviour rather than to a crash.
|
|
30
|
-
*/
|
|
31
|
-
export declare const VENDOR_TOOL_USE_ID_META_KEY = "claudecode/toolUseId";
|
|
32
|
-
export declare function toolUseIdFromExtra(extra: unknown): string | undefined;
|
|
33
|
-
export interface MessagingToolHandlers {
|
|
34
|
-
sendMessage: MessagingToolHandler;
|
|
35
|
-
listAgents: MessagingToolHandler;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* WHO IS CALLING — bound at registration, never read out of the arguments.
|
|
39
|
-
*
|
|
40
|
-
* The standing MCP server is materialized per session (WS-14 §11), so the caller is known when the
|
|
41
|
-
* handler is built. Taking it from the ARGUMENTS instead would make the sender's identity something a
|
|
42
|
-
* model could write, and every fence in this package — the owning-parent rule, the self-target
|
|
43
|
-
* refusal, WS-10 §13's sender class, WS-15 §6.2's dedupe key — is keyed on it.
|
|
44
|
-
*
|
|
45
|
-
* `toolUseId` is the second half of WS-10 §12's retry key. It is OPTIONAL because on the official
|
|
46
|
-
* branch it is not available: the in-process MCP server hands a tool handler its arguments, and the
|
|
47
|
-
* router's own materialization does not forward the vendor's `extra` (which is where a request id
|
|
48
|
-
* would be). A caller that cannot supply one gets no dedupe — stated at the door rather than faked
|
|
49
|
-
* with a stable-looking key that would make two different messages one.
|
|
50
|
-
*/
|
|
51
|
-
export interface MessagingToolCaller {
|
|
52
|
-
sessionId: string;
|
|
53
|
-
agentId?: string;
|
|
54
|
-
toolUseId?: string;
|
|
55
|
-
}
|
|
56
|
-
export declare function createMessagingToolHandlers(messaging: GlobalMessagingHandle, caller: MessagingToolCaller | (() => MessagingToolCaller)): MessagingToolHandlers;
|
package/dist/native-args.d.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/** WS-10 §10.1's bounds. `to`'s own limit is the subpath's; this is the copy the SCHEMA advertises. */
|
|
2
|
-
export declare const SEND_MESSAGE_TO_MAX = 300;
|
|
3
|
-
export declare const SEND_MESSAGE_SUMMARY_MAX = 200;
|
|
4
|
-
/** WS-10 §10.2's bound on both reserved `ListAgents` fields. */
|
|
5
|
-
export declare const LIST_AGENTS_FIELD_MAX = 256;
|
|
6
|
-
export declare const NATIVE_SEND_MESSAGE_SCHEMA: {
|
|
7
|
-
readonly type: "object";
|
|
8
|
-
readonly properties: {
|
|
9
|
-
readonly to: {
|
|
10
|
-
readonly type: "string";
|
|
11
|
-
readonly maxLength: 300;
|
|
12
|
-
readonly description: "no newline, no \"*\" broadcast";
|
|
13
|
-
};
|
|
14
|
-
readonly message: {
|
|
15
|
-
readonly type: "string";
|
|
16
|
-
readonly description: "required; defaults \"\" for pure idle subscription";
|
|
17
|
-
};
|
|
18
|
-
readonly summary: {
|
|
19
|
-
readonly type: "string";
|
|
20
|
-
readonly maxLength: 200;
|
|
21
|
-
};
|
|
22
|
-
readonly notify_when_idle: {
|
|
23
|
-
readonly type: "boolean";
|
|
24
|
-
readonly description: "one-shot; main conversation -> same-machine session only";
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
readonly required: readonly ["to", "message"];
|
|
28
|
-
};
|
|
29
|
-
export declare const NATIVE_LIST_AGENTS_SCHEMA: {
|
|
30
|
-
readonly type: "object";
|
|
31
|
-
readonly properties: {
|
|
32
|
-
readonly channel: {
|
|
33
|
-
readonly type: "string";
|
|
34
|
-
readonly maxLength: 256;
|
|
35
|
-
readonly description: "reserved";
|
|
36
|
-
};
|
|
37
|
-
readonly q: {
|
|
38
|
-
readonly type: "string";
|
|
39
|
-
readonly maxLength: 256;
|
|
40
|
-
readonly description: "reserved";
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
};
|
|
44
|
-
/** WS-10 §10.2: "`ListAgents` output is EXACTLY `{ listing: string }`." */
|
|
45
|
-
export declare const NATIVE_LIST_AGENTS_OUTPUT_SCHEMA: {
|
|
46
|
-
readonly type: "object";
|
|
47
|
-
readonly properties: {
|
|
48
|
-
readonly listing: {
|
|
49
|
-
readonly type: "string";
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
|
-
readonly required: readonly ["listing"];
|
|
53
|
-
};
|
|
54
|
-
/** The native `SendMessage` arguments (WS-10 §10.1), after validation. */
|
|
55
|
-
export interface NativeSendMessageArgs {
|
|
56
|
-
to: string;
|
|
57
|
-
message: string;
|
|
58
|
-
summary?: string;
|
|
59
|
-
notify_when_idle?: boolean;
|
|
60
|
-
}
|
|
61
|
-
/** The native `ListAgents` arguments (WS-10 §10.2). Both fields are reserved in the pinned build. */
|
|
62
|
-
export interface NativeListAgentsArgs {
|
|
63
|
-
channel?: string;
|
|
64
|
-
q?: string;
|
|
65
|
-
}
|
|
66
|
-
export type NativeArgsResult<T> = {
|
|
67
|
-
ok: true;
|
|
68
|
-
args: T;
|
|
69
|
-
} | {
|
|
70
|
-
ok: false;
|
|
71
|
-
reason: string;
|
|
72
|
-
};
|
|
73
|
-
/** Accepts the native `SendMessage` arguments EXACTLY — no more, no less. */
|
|
74
|
-
export declare function acceptNativeSendMessageArgs(input: unknown): NativeArgsResult<NativeSendMessageArgs>;
|
|
75
|
-
/** The same treatment for `ListAgents`: two reserved optional fields, both capped, nothing else. */
|
|
76
|
-
export declare function acceptNativeListAgentsArgs(input: unknown): NativeArgsResult<NativeListAgentsArgs>;
|