@yanlinglabs/winter-agent-runtime 0.0.27 → 0.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -53,7 +53,8 @@ import {
53
53
  DEFAULT_CLASSIFIER_TIMEOUT_MS2,
54
54
  createModelClassifier2,
55
55
  selectClassifierRoute2
56
- } from "./index-9qgkpv56.js";
56
+ } from "./index-jz5d90c6.js";
57
+ import"./index-8jgwp1px.js";
57
58
  import"./index-bef62z3r.js";
58
59
  import {
59
60
  createInMemoryChannel2
@@ -1,7 +1,22 @@
1
1
  import type { McpServerConfigForProcessTransport, McpVersionNegotiation } from "@yanlinglabs/winter-agent-sdk";
2
2
  import { type InProcessMcpServer } from "./transports/sdk.js";
3
3
  import { type ElicitationAsker } from "./elicitation.js";
4
- export type McpConnectErrorCode = "timeout" | "spawn_failed" | "handshake_failed" | "needs_auth" | "unknown";
4
+ /**
5
+ * WHY a connection attempt failed -- a category, not a message (the message is for humans; this is what
6
+ * the state board's `errorCode`, the web search backend and the `'auto'` legacy retry read).
7
+ *
8
+ * WS-24 split two causes out of `handshake_failed`, which a failed version negotiation used to land in
9
+ * whatever had gone wrong:
10
+ * - `version_mismatch`: the server and this client share no protocol version -- a `{pin}` the server
11
+ * did not offer, or a server that named the versions it speaks and none is ours. Retrying cannot
12
+ * help, so the `'auto'` legacy retry never spends a second connection on it.
13
+ * - `transport_closed`: the server ended the connection under the attempt -- a stdio server that
14
+ * exited by itself (on the `server/discover` probe, or during `initialize`). Observed on the
15
+ * transport (`WinterStdioTransport.exitedOnItsOwn`), never inferred from message text.
16
+ * A probe that went unanswered is `timeout` and a probe answered with an HTTP error keeps
17
+ * `handshake_failed` plus its `httpStatus`, as before.
18
+ */
19
+ export type McpConnectErrorCode = "timeout" | "spawn_failed" | "handshake_failed" | "version_mismatch" | "transport_closed" | "needs_auth" | "unknown";
5
20
  export declare class McpConnectError extends Error {
6
21
  readonly code: McpConnectErrorCode;
7
22
  /**
@@ -59,6 +59,8 @@ export declare function stdioFixtureCommand(): {
59
59
  export declare function pingFixtureCommand(opts?: {
60
60
  label?: string;
61
61
  delayMs?: number;
62
+ onProbe?: "answer" | "silent" | "exit";
63
+ spawnLog?: string;
62
64
  }): {
63
65
  command: string;
64
66
  args: string[];
@@ -20,11 +20,30 @@ export declare class WinterStdioTransport implements Transport {
20
20
  private child;
21
21
  private readonly readBuffer;
22
22
  private stderrTailBuffer;
23
+ private exitedOnItsOwnFlag;
23
24
  onclose?: () => void;
24
25
  onerror?: (error: Error) => void;
25
26
  onmessage?: (message: JSONRPCMessage) => void;
26
27
  constructor(opts: WinterStdioTransportOptions);
27
28
  get pid(): number | null;
29
+ /**
30
+ * WS-24: the running child's stderr stream (`null` before `start()` and after exit) -- the shape of
31
+ * the SDK's own `StdioClientTransport.stderr`. Declared for one reason: the v2 client decides how to
32
+ * read a `server/discover` probe by DUCK TYPING (`"stderr" in transport && "pid" in transport` ->
33
+ * "stdio"), and only as stdio does an unanswered probe settle the LEGACY era on the same pipe (a
34
+ * server that ignores unknown methods keeps its one process); read as "http", the silence is an outage
35
+ * and `connectMcpServer`'s legacy retry has to respawn the server. `client.test.ts` pins the single
36
+ * spawn, so a future client that stops recognising this transport fails there, not silently. Nothing
37
+ * reads from the stream through this getter: the tail below stays the one reader.
38
+ */
39
+ get stderr(): NodeJS.ReadableStream | null;
40
+ /**
41
+ * WS-24: the server exited BY ITSELF -- its process closed while this transport still held it, never
42
+ * through `close()` (which lets go of the child before killing it). This is how `connectMcpServer`
43
+ * tells a server that died under the attempt (`transport_closed`: e.g. one that exits on the
44
+ * `server/discover` probe) from one the client tore down after a failed attempt of its own.
45
+ */
46
+ get exitedOnItsOwn(): boolean;
28
47
  start(): Promise<void>;
29
48
  get stderrTail(): string;
30
49
  private withStderrTail;
@@ -0,0 +1,28 @@
1
+ import type { McpServerConfigForProcessTransport } from "@yanlinglabs/winter-agent-sdk";
2
+ import { type ConnectedMcpClient } from "./mcp/client.js";
3
+ import type { ElicitationAsker } from "./mcp/elicitation.js";
4
+ export { McpConnectError, resolveVersionNegotiation, type ConnectedMcpClient, type McpConnectErrorCode, type McpToolInfo, type McpToolAnnotationsInfo, type McpResourceInfo, type McpResourceContent, type McpToolCallResult, } from "./mcp/client.js";
5
+ export { createElicitationAsker, type ElicitationAction, type ElicitationAsker, type ElicitationRequestPayload, type ElicitationResultPayload, type ElicitationSender, } from "./mcp/elicitation.js";
6
+ /**
7
+ * What a HOST connects with -- deliberately narrower than the runtime's own options: no in-process
8
+ * (`type: "sdk"`) server (a host that has the server object in hand does not need a protocol client to
9
+ * reach it), no redirect refusal (the runtime's web search backend's concern) and no list-changed hook
10
+ * (the runtime's lifecycle owns re-registration). Everything it references is exported from here or from
11
+ * `@yanlinglabs/winter-agent-sdk`, so this subpath's declarations reach into nothing private.
12
+ */
13
+ export interface ConnectMcpServerOptions {
14
+ /** The server's name: prefixes its diagnostics and is `ConnectedMcpClient.serverName`. */
15
+ name: string;
16
+ /** A stdio, Streamable HTTP or SSE server config (with its optional `versionNegotiation`). */
17
+ config: Exclude<McpServerConfigForProcessTransport, {
18
+ type: "sdk";
19
+ }>;
20
+ /** The connection attempt's whole budget, in ms (never a tool call's timeout). */
21
+ connectTimeoutMs: number;
22
+ /** Answers a server's elicitation; `createElicitationAsker(undefined)` declines every one deterministically. */
23
+ elicitationAsk: ElicitationAsker;
24
+ /** REQUIRED for a stdio server: the directory it starts in (never the host process's cwd by default). */
25
+ cwd?: string;
26
+ }
27
+ /** Connect ONE MCP server and return its live client. Rejects with a typed `McpConnectError` (see its `code`). */
28
+ export declare function connectMcpServer(opts: ConnectMcpServerOptions): Promise<ConnectedMcpClient>;
@@ -0,0 +1,23 @@
1
+ import {
2
+ createElicitationAsker2,
3
+ McpConnectError2,
4
+ resolveVersionNegotiation2,
5
+ connectMcpServer2
6
+ } from "./index-8jgwp1px.js";
7
+
8
+ // src/mcp-client.ts
9
+ function connectMcpServer(opts) {
10
+ return connectMcpServer2({
11
+ name: opts.name,
12
+ config: opts.config,
13
+ connectTimeoutMs: opts.connectTimeoutMs,
14
+ elicitationAsk: opts.elicitationAsk,
15
+ ...opts.cwd !== undefined ? { cwd: opts.cwd } : {}
16
+ });
17
+ }
18
+ export {
19
+ McpConnectError2 as McpConnectError,
20
+ connectMcpServer,
21
+ createElicitationAsker2 as createElicitationAsker,
22
+ resolveVersionNegotiation2 as resolveVersionNegotiation
23
+ };
@@ -18,6 +18,11 @@ export interface SymlinkBothEndsResult {
18
18
  }
19
19
  export declare function resolveRealTarget(path: string): string;
20
20
  export declare function resolveSymlinkTargetChain(path: string): string | undefined;
21
+ export interface SymlinkEnds {
22
+ target: string;
23
+ chainTarget: string | undefined;
24
+ }
25
+ export declare function resolveSymlinkEnds(path: string): SymlinkEnds;
21
26
  export declare function checkSymlinkBothEnds(path: string, matcher: (candidatePath: string) => boolean): SymlinkBothEndsResult;
22
27
  export declare function matchFileRuleAtBothEnds(pattern: string, opts: MatchFileRuleOptions): boolean;
23
28
  export interface FileRuleEntry {
@@ -0,0 +1,22 @@
1
+ /** Which spawn site a group came from -- for diagnostics only; the host treats every group alike. */
2
+ export type ProcessGroupKind = "command" | "mcp_stdio" | "hook" | "workflow";
3
+ export interface ProcessGroupChange {
4
+ op: "add" | "remove";
5
+ pgid: number;
6
+ kind: ProcessGroupKind;
7
+ }
8
+ /**
9
+ * Record `pgid` (the pid of a child spawned `detached: true`, i.e. its group leader) as live. Returns
10
+ * the release, which is idempotent -- a spawn site may reach its "the leader is gone" point by more
11
+ * than one path (`close` after `error`, an explicit `close()` racing the exit event).
12
+ */
13
+ export declare function trackProcessGroup(pgid: number, kind: ProcessGroupKind): () => void;
14
+ /** Every group currently recorded as live, oldest first. */
15
+ export declare function liveProcessGroups(): ReadonlyArray<{
16
+ pgid: number;
17
+ kind: ProcessGroupKind;
18
+ }>;
19
+ /** Observe every add/remove from now on. Returns the unsubscribe. */
20
+ export declare function onProcessGroupChange(listener: (change: ProcessGroupChange) => void): () => void;
21
+ /** Test seam: forget everything (a test that spawns and kills in one realm must not see another test's groups). */
22
+ export declare function resetProcessGroupsForTest(): void;
@@ -23,6 +23,18 @@ export interface ModelClassifierOptions {
23
23
  maxContextChars?: number;
24
24
  /** P7a fix wave (item 5, M-1): the running brand's instructions file, so the classifier prompt labels the operator's own file correctly. */
25
25
  instructionsFile?: string;
26
+ /**
27
+ * WS-24 (M-1 fix round): whether this row's descriptor lists `tool_choice.tool` in its
28
+ * `unsupportedParameters` -- the SAME evidence `resolveToolChoice` (`adapters/anthropic/
29
+ * messages.ts`) gates its forced-choice-to-`auto` downgrade on (today: the anthropic/console Opus
30
+ * 5.5 and Fable 5.1 rows). ONLY on such a row does a text reply get the text-fallback path
31
+ * (`collapseTextFallback`): the request's own forced `tool_choice` is a documented lie for it, so a
32
+ * text reply is the expected shape of an honest answer, not a misbehaving model. Everywhere else, a
33
+ * text reply IS a misbehaving model (a real forced choice reached it and it ignored the tool
34
+ * anyway) and stays `no_tool_call` -- never given a chance to recover, which would otherwise let
35
+ * ANY model's ordinary refusal-to-call-the-tool quietly become a verdict. Defaults to `false`.
36
+ */
37
+ forcedToolChoiceUnsupported?: boolean;
26
38
  /**
27
39
  * Test seam: observes what was actually sent and what came back, WITHOUT the classifier logging
28
40
  * anything itself. Nothing in this file writes to a log — a permission review's request contains
@@ -478,7 +478,7 @@ export declare class TranscriptWriter implements SessionPersistence {
478
478
  private dialectRecord;
479
479
  static readBack(store: SessionStore, key: SessionKey): Promise<SessionStoreEntry[]>;
480
480
  }
481
- export declare const RUNTIME_ENGINE_VERSION = "0.0.27";
481
+ export declare const RUNTIME_ENGINE_VERSION = "0.0.29";
482
482
  export interface ResolvedEngineSession {
483
483
  config: RuntimeConfig;
484
484
  store: SessionPersistence | undefined;
@@ -21,7 +21,20 @@ export declare const PROVIDER_STATE_SUBPATH: "provider-state";
21
21
  * they cannot drift from what the deletion transaction actually removes.
22
22
  */
23
23
  export { PROVIDER_STATE_FILE_SUFFIX };
24
- export type ProviderStateKind = "origin" | "native-state" | "summary" | "handoff" | "reasoning-blocks" | "effort" | "tool-epoch" | "tool-changes" | "decoration";
24
+ export type ProviderStateKind = "origin" | "native-state" | "summary" | "handoff" | "reasoning-blocks" | "effort" | "tool-epoch" | "tool-changes" | "decoration" | "feature-rejected";
25
+ /**
26
+ * WS-24: the request features an API can refuse once and the session then stops sending, on that
27
+ * provider+model: the per-message effort beta, a mid-conversation tool change, OpenAI's client
28
+ * `tool_search`, and `tool_choice: allowed_tools`.
29
+ */
30
+ export declare const REJECTABLE_FEATURES: readonly ["per-message-effort", "tool-changes", "client-tool-search", "allowed-tools"];
31
+ export type RejectableFeature = (typeof REJECTABLE_FEATURES)[number];
32
+ /** WS-24: every `feature-rejected` record, as `{provider, model, feature}` -- anchor presence is deliberately not consulted (see the kind's note above). */
33
+ export declare function rejectedFeaturesFrom(records: readonly ProviderStateRecord[]): Array<{
34
+ provider: string;
35
+ model: string;
36
+ feature: RejectableFeature;
37
+ }>;
25
38
  /**
26
39
  * One sidecar record. The envelope (`type`/`uuid`/`timestamp`) plus R6-7's own payload fields.
27
40
  *
@@ -328,6 +328,14 @@ export interface ParentMcpState {
328
328
  * `JP($n, Y2(yr.mcp.tools.concat(pn)))`, dump byte 18016381).
329
329
  */
330
330
  visibleServerNames?: () => readonly string[];
331
+ /**
332
+ * WS-24 (fix round 3): the parent run's own `EngineOptions.mcpServerRenames` -- `{ actual: declared }`
333
+ * for every server in its scope that runs under a name other than the one it was declared with. A
334
+ * renamed server is in `visibleServerNames` above, so a descendant can call it; the descendant merges
335
+ * these into its own renames, so session rules and hooks written against the declared name keep
336
+ * governing it at every depth.
337
+ */
338
+ serverRenames?: Readonly<Record<string, string>>;
331
339
  }
332
340
  export interface ParentRuleMirror {
333
341
  allow: string[];
package/dist/testing.js CHANGED
@@ -3,7 +3,8 @@ import {
3
3
  runEngine2,
4
4
  echoProvider2,
5
5
  resolveEngineSession2
6
- } from "./index-9qgkpv56.js";
6
+ } from "./index-jz5d90c6.js";
7
+ import"./index-8jgwp1px.js";
7
8
  import"./index-bef62z3r.js";
8
9
  import {
9
10
  registerDefaultChildEngineFactory,
@@ -11,7 +12,7 @@ import {
11
12
  buildProductionWiring,
12
13
  withAutoSkillPermissions,
13
14
  restoreChildRoster
14
- } from "./index-584yahed.js";
15
+ } from "./index-gmxxtqpe.js";
15
16
  import {
16
17
  Queue
17
18
  } from "./index-97t2rmtf.js";
@@ -297,6 +297,12 @@ export declare function registerMcpServerTools(server: string, incomingTools: re
297
297
  * servers that run can see (engine.ts's `computeAdvertisedPartition`).
298
298
  */
299
299
  export declare function mcpServerOwningTool(canonicalName: string): string | undefined;
300
+ /**
301
+ * WS-24: does a live MCP server currently hold registrations under `server`? A subagent's own
302
+ * object-form server must not take a name some other lifecycle in this process is registered under --
303
+ * see subagents/child-engine.ts's `allocateChildScopedServers`.
304
+ */
305
+ export declare function mcpServerHasRegistrations(server: string): boolean;
300
306
  export declare function unregisterMcpServerTools(server: string): void;
301
307
  export interface LoadedToolSet {
302
308
  isLoaded(name: string): boolean;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const RUNTIME_VERSION = "0.0.27";
1
+ export declare const RUNTIME_VERSION = "0.0.29";
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var RUNTIME_VERSION = "0.0.27";
2
+ var RUNTIME_VERSION = "0.0.29";
3
3
  export {
4
4
  RUNTIME_VERSION
5
5
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yanlinglabs/winter-agent-runtime",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "engines": {
@@ -45,6 +45,10 @@
45
45
  "./version": {
46
46
  "types": "./dist/version.d.ts",
47
47
  "default": "./dist/version.js"
48
+ },
49
+ "./mcp-client": {
50
+ "types": "./dist/mcp-client.d.ts",
51
+ "default": "./dist/mcp-client.js"
48
52
  }
49
53
  },
50
54
  "files": [
@@ -65,9 +69,9 @@
65
69
  "@modelcontextprotocol/client": "^2.1.0",
66
70
  "ajv": "^8.20.0",
67
71
  "ignore": "7.0.5",
68
- "@yanlinglabs/winter-provider-runtime": "0.0.27",
69
- "@yanlinglabs/winter-agent-sdk": "0.0.27",
70
- "@yanlinglabs/winter-provider-catalog": "0.0.27"
72
+ "@yanlinglabs/winter-agent-sdk": "0.0.29",
73
+ "@yanlinglabs/winter-provider-catalog": "0.0.29",
74
+ "@yanlinglabs/winter-provider-runtime": "0.0.29"
71
75
  },
72
76
  "devDependencies": {
73
77
  "@modelcontextprotocol/server": "^2.1.0"