@apnex/network-adapter 0.1.1 → 0.1.5

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.
Files changed (86) hide show
  1. package/dist/build-info.json +6 -0
  2. package/dist/file-logger.d.ts +42 -0
  3. package/dist/file-logger.js +122 -0
  4. package/dist/file-logger.js.map +1 -0
  5. package/dist/index.d.ts +37 -13
  6. package/dist/index.js +42 -15
  7. package/dist/index.js.map +1 -1
  8. package/dist/kernel/adapter-config.d.ts +47 -0
  9. package/dist/kernel/adapter-config.js +90 -0
  10. package/dist/kernel/adapter-config.js.map +1 -0
  11. package/dist/kernel/agent-client.d.ts +25 -20
  12. package/dist/kernel/build-identity.d.ts +24 -0
  13. package/dist/kernel/build-identity.js +45 -0
  14. package/dist/kernel/build-identity.js.map +1 -0
  15. package/dist/kernel/event-router.d.ts +22 -1
  16. package/dist/kernel/event-router.js +45 -7
  17. package/dist/kernel/event-router.js.map +1 -1
  18. package/dist/kernel/handshake.d.ts +40 -4
  19. package/dist/kernel/handshake.js +46 -7
  20. package/dist/kernel/handshake.js.map +1 -1
  21. package/dist/kernel/harness-manifest.d.ts +51 -0
  22. package/dist/kernel/harness-manifest.js +96 -0
  23. package/dist/kernel/harness-manifest.js.map +1 -0
  24. package/dist/kernel/liveness-signal.d.ts +35 -0
  25. package/dist/kernel/liveness-signal.js +61 -0
  26. package/dist/kernel/liveness-signal.js.map +1 -0
  27. package/dist/kernel/liveness-watchdog.d.ts +78 -0
  28. package/dist/kernel/liveness-watchdog.js +115 -0
  29. package/dist/kernel/liveness-watchdog.js.map +1 -0
  30. package/dist/kernel/mcp-agent-client.d.ts +2 -2
  31. package/dist/kernel/mcp-agent-client.js +49 -3
  32. package/dist/kernel/mcp-agent-client.js.map +1 -1
  33. package/dist/kernel/poll-backstop.d.ts +93 -4
  34. package/dist/kernel/poll-backstop.js +193 -25
  35. package/dist/kernel/poll-backstop.js.map +1 -1
  36. package/dist/kernel/state-sync.d.ts +2 -13
  37. package/dist/kernel/state-sync.js.map +1 -1
  38. package/dist/notification-log.d.ts +8 -0
  39. package/dist/notification-log.js +10 -0
  40. package/dist/notification-log.js.map +1 -1
  41. package/dist/observability.d.ts +24 -0
  42. package/dist/observability.js +52 -0
  43. package/dist/observability.js.map +1 -0
  44. package/dist/prompt-format.js +82 -9
  45. package/dist/prompt-format.js.map +1 -1
  46. package/dist/tool-manager/catalog/health-revision.d.ts +43 -0
  47. package/dist/tool-manager/catalog/health-revision.js +61 -0
  48. package/dist/tool-manager/catalog/health-revision.js.map +1 -0
  49. package/dist/tool-manager/{tool-catalog-cache.d.ts → catalog/tool-catalog-cache.d.ts} +39 -19
  50. package/dist/tool-manager/{tool-catalog-cache.js → catalog/tool-catalog-cache.js} +53 -26
  51. package/dist/tool-manager/catalog/tool-catalog-cache.js.map +1 -0
  52. package/dist/tool-manager/catalog/tool-surface-reconciler.d.ts +93 -0
  53. package/dist/tool-manager/catalog/tool-surface-reconciler.js +101 -0
  54. package/dist/tool-manager/catalog/tool-surface-reconciler.js.map +1 -0
  55. package/dist/tool-manager/contracts.d.ts +91 -0
  56. package/dist/tool-manager/contracts.js +20 -0
  57. package/dist/tool-manager/contracts.js.map +1 -0
  58. package/dist/tool-manager/dispatch/dispatch.d.ts +77 -0
  59. package/dist/tool-manager/dispatch/dispatch.js +170 -0
  60. package/dist/tool-manager/dispatch/dispatch.js.map +1 -0
  61. package/dist/tool-manager/dispatch/tool-call-policy.d.ts +32 -0
  62. package/dist/tool-manager/dispatch/tool-call-policy.js +56 -0
  63. package/dist/tool-manager/dispatch/tool-call-policy.js.map +1 -0
  64. package/dist/tool-manager/{dispatcher.d.ts → orchestrator/dispatcher.d.ts} +110 -31
  65. package/dist/tool-manager/orchestrator/dispatcher.js +559 -0
  66. package/dist/tool-manager/orchestrator/dispatcher.js.map +1 -0
  67. package/dist/tool-manager/work-protocol/claimable-digest-tracker.d.ts +60 -0
  68. package/dist/tool-manager/work-protocol/claimable-digest-tracker.js +66 -0
  69. package/dist/tool-manager/work-protocol/claimable-digest-tracker.js.map +1 -0
  70. package/dist/tool-manager/work-protocol/work-lease-tracker.d.ts +59 -0
  71. package/dist/tool-manager/work-protocol/work-lease-tracker.js +134 -0
  72. package/dist/tool-manager/work-protocol/work-lease-tracker.js.map +1 -0
  73. package/dist/wire/mcp-transport.d.ts +1 -1
  74. package/dist/wire/mcp-transport.js +31 -7
  75. package/dist/wire/mcp-transport.js.map +1 -1
  76. package/dist/wire/slot-gate.d.ts +40 -0
  77. package/dist/wire/slot-gate.js +61 -0
  78. package/dist/wire/slot-gate.js.map +1 -0
  79. package/dist/wire/transport.d.ts +18 -0
  80. package/package.json +6 -3
  81. package/dist/kernel/instance.d.ts +0 -40
  82. package/dist/kernel/instance.js +0 -79
  83. package/dist/kernel/instance.js.map +0 -1
  84. package/dist/tool-manager/dispatcher.js +0 -379
  85. package/dist/tool-manager/dispatcher.js.map +0 -1
  86. package/dist/tool-manager/tool-catalog-cache.js.map +0 -1
@@ -19,11 +19,13 @@
19
19
  * "dispatcher".
20
20
  */
21
21
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
22
- import type { AgentClientCallbacks, AgentEvent, SessionState, SessionReconnectReason } from "../kernel/agent-client.js";
23
- import type { McpAgentClient } from "../kernel/mcp-agent-client.js";
24
- import { PollBackstop, type PollBackstopOptions } from "../kernel/poll-backstop.js";
25
- import type { DrainedPendingAction } from "../kernel/state-sync.js";
26
- import type { CachedCatalog } from "./tool-catalog-cache.js";
22
+ import type { AgentClientCallbacks, AgentEvent, SessionState, SessionReconnectReason } from "../../kernel/agent-client.js";
23
+ import type { McpAgentClient } from "../../kernel/mcp-agent-client.js";
24
+ import { PollBackstop, type PollBackstopOptions } from "../../kernel/poll-backstop.js";
25
+ import type { DrainedPendingAction } from "../../kernel/state-sync.js";
26
+ import type { CachedCatalog } from "../catalog/tool-catalog-cache.js";
27
+ import { WorkLeaseTracker } from "../work-protocol/work-lease-tracker.js";
28
+ import { TOOL_CALL_SIGNAL_SKIP, pendingKey, injectQueueItemId } from "../dispatch/tool-call-policy.js";
27
29
  export interface DispatcherClientInfo {
28
30
  name: string;
29
31
  version: string;
@@ -47,8 +49,11 @@ export interface SharedDispatcherOptions {
47
49
  * Late-binding agent accessor. Some hosts (opencode) construct the
48
50
  * dispatcher before the McpAgentClient connection is established.
49
51
  * Returning `null` means "not connected yet" — the dispatcher
50
- * surfaces a "Hub not connected" error envelope on CallTool and an
51
- * empty tool-list on ListTools.
52
+ * surfaces a "Hub not connected" error envelope on CallTool and a
53
+ * structured MCP error on ListTools after a bounded retry window
54
+ * (bug-114 fallback-gap fix). Silent empty-tool-list response was
55
+ * retired 2026-05-26 — host MCP clients (e.g. Claude Code) cached
56
+ * the empty list as the authoritative surface, masking comms-loss.
52
57
  */
53
58
  getAgent: () => McpAgentClient | null;
54
59
  /** Adapter version reported in MCP serverInfo. */
@@ -64,10 +69,19 @@ export interface SharedDispatcherOptions {
64
69
  /** Diagnostic logger. No-op default. */
65
70
  log?: (msg: string) => void;
66
71
  /**
67
- * Resolves when the underlying McpAgentClient handshake completes
68
- * (transport connected + identity asserted). Gates the ListTools
69
- * handler so the host's catalog fetch doesn't block on the slow
70
- * full-sync phase. Omit when no gating is needed (tests).
72
+ * Resolves when the underlying McpAgentClient is fully usable
73
+ * (transport connected + identity asserted + streaming-state
74
+ * reached, i.e. `agent.start()` returned). Gates the ListTools
75
+ * handler's bootstrap path; on probe-path (`!identityReady`) the
76
+ * cache fallback runs without awaiting this gate.
77
+ *
78
+ * bug-141 pass-2 (2026-05-28): docs updated from "handshake
79
+ * completes" → "fully usable". The earlier wording prompted host
80
+ * shims to gate on `identityReady`, which opened the gate ~1.3s
81
+ * before `agent.isConnected` flipped true (during the synchronizing
82
+ * → streaming transition) — surfacing the bug-141 race. Hosts MUST
83
+ * gate on a Promise that resolves only after the agent is in
84
+ * streaming state (claude-plugin: `syncReady`).
71
85
  *
72
86
  * Was: `handshakeComplete` (per-plugin dispatchers). Renamed in
73
87
  * mission-55 cleanup per Design v1.2 Q5: name what is gated, not
@@ -84,22 +98,47 @@ export interface SharedDispatcherOptions {
84
98
  * cleanup per Design v1.2 Q5.
85
99
  */
86
100
  callToolGate?: Promise<void>;
101
+ /**
102
+ * mission-88 W10 (bug-126 fix): timeout in ms for `await callToolGate`.
103
+ * If the gate Promise neither resolves nor rejects within this budget,
104
+ * the dispatcher emits a structured `gate-timeout` log line + returns
105
+ * isError to host (instead of hanging indefinitely as the bug-126
106
+ * incident exhibited). Default 30000ms; set to 0 to disable.
107
+ *
108
+ * Defense against pending-forever sessionReady Promises (W10 Design §3
109
+ * H1+H3 hypotheses). The timeout is a fail-safe — production-correct
110
+ * handshake flow should never hit it.
111
+ */
112
+ callToolGateTimeoutMs?: number;
87
113
  getCachedCatalog?: () => CachedCatalog | null;
88
114
  getIsIdentityReady?: () => boolean;
89
- getCurrentHubVersion?: () => string | null;
115
+ /**
116
+ * bug-114 — current Hub tool-surface revision (`/health`
117
+ * `toolSurfaceRevision`). The cache-validity key; `null` when the
118
+ * /health fetch hasn't resolved yet (probe-friendly trust-cache).
119
+ */
120
+ getCurrentToolSurfaceRevision?: () => string | null;
90
121
  persistCatalog?: (catalog: unknown[]) => void;
91
122
  /**
92
123
  * Optional cache-validity check. When omitted, cache-fallback
93
124
  * conservatively treats every cached entry as invalid (live-fetch
94
125
  * dominates). Wire `isCacheValid` from `./tool-catalog-cache.js`
95
- * to enable Hub-version-keyed validity.
126
+ * to enable tool-surface-revision-keyed validity.
96
127
  */
97
- isCacheValid?: (cached: CachedCatalog, currentHubVersion: string | null | undefined) => boolean;
128
+ isCacheValid?: (cached: CachedCatalog, currentRevision: string | null | undefined) => boolean;
98
129
  /**
99
130
  * Universal Adapter notification contract. Host shim attaches its
100
131
  * render-surface bindings here.
101
132
  */
102
133
  notificationHooks?: DispatcherNotificationHooks;
134
+ /**
135
+ * idea-353 W2: observe each host-driven CallTool's (method, args, result)
136
+ * after it returns. The host wires this to a WorkLeaseTracker so the
137
+ * outbound stall-prompt can track this agent's own held leases locally
138
+ * (claim/renew/complete/abandon) with no Hub round-trip. Best-effort —
139
+ * a throw is caught + logged and never affects the tool-call return.
140
+ */
141
+ onToolCallResult?: (method: string, args: Record<string, unknown>, result: unknown) => void;
103
142
  /**
104
143
  * Mission-56 W3.3: opt-in adapter-side hybrid poll backstop. When
105
144
  * supplied, the dispatcher constructs a PollBackstop (Design v1.2
@@ -113,6 +152,24 @@ export interface SharedDispatcherOptions {
113
152
  * Omit to disable polling (push-only mode).
114
153
  */
115
154
  pollBackstop?: Omit<PollBackstopOptions, "onPolledMessage">;
155
+ /**
156
+ * Slice D (pi native binding) — external idle probe. A NATIVE host (pi) drives
157
+ * tool calls through `runToolDispatch` directly, NOT through this dispatcher's
158
+ * MCP `CallTool` handler, so the internal `activeCallCount` never sees them.
159
+ * Supply the host's own idle signal (e.g. pi's `ctx.isIdle()`) and the
160
+ * wake/stall reconcile gates on THAT instead of the (always-zero) internal
161
+ * counter. When omitted, the internal `activeCallCount` is authoritative
162
+ * (MCP hosts — unchanged).
163
+ */
164
+ externalIdle?: () => boolean;
165
+ /**
166
+ * Slice D (pi native binding) — shared WorkLeaseTracker. A native host's
167
+ * `ToolDispatchContext.workLeases` must be the SAME tracker the reconcile
168
+ * reads for stall-prompts. Inject it here so the native binding's
169
+ * `workLeases.observe(...)` populates the tracker the heartbeat tick consumes.
170
+ * When omitted, the dispatcher constructs its own (MCP hosts — unchanged).
171
+ */
172
+ sharedWorkLeases?: WorkLeaseTracker;
116
173
  }
117
174
  export interface SharedDispatcher {
118
175
  /** ADR-017 queueItemId tracking map. Keyed by `${dispatchType}:${entityRef}`. */
@@ -157,24 +214,46 @@ export interface SharedDispatcher {
157
214
  * re-render it.
158
215
  */
159
216
  ackMessage: (messageId: string) => Promise<void>;
217
+ /**
218
+ * idea-353 W1 idle-gate: number of host-driven CallTool requests currently
219
+ * in flight. The wake/stall reconciler reads this on the heartbeat tick to
220
+ * skip surfacing while the agent is mid-task (AC4). The tick's own internal
221
+ * `agent.call`s do not pass through the CallTool handler, so they are not
222
+ * counted (an idle poll never self-gates).
223
+ */
224
+ getActiveCallCount: () => number;
225
+ /** idea-353 W1 idle-gate convenience: `getActiveCallCount() === 0`. */
226
+ isIdle: () => boolean;
227
+ /**
228
+ * Slice D (pi native binding) — the WorkLeaseTracker the reconcile reads. A
229
+ * native host builds its `ToolDispatchContext.workLeases` from THIS instance
230
+ * so its `runToolDispatch` lease observations feed the stall-prompt path.
231
+ * (Same object as `opts.sharedWorkLeases` when injected.)
232
+ */
233
+ workLeases: WorkLeaseTracker;
160
234
  }
161
- /** Compose the pendingActionMap key. Pure helper; exported for tests. */
162
- /**
163
- * Mission-62 W3: tools that should NOT trigger signal_working_*
164
- * wrapping. The signal_* tools themselves would recurse infinitely;
165
- * register_role + claim_session + drain_pending_actions are lifecycle
166
- * tools, not semantic tool-call-work.
167
- */
168
- export declare const TOOL_CALL_SIGNAL_SKIP: ReadonlySet<string>;
169
- export declare function pendingKey(dispatchType: string, entityRef: string): string;
235
+ export { TOOL_CALL_SIGNAL_SKIP, pendingKey, injectQueueItemId };
236
+ export declare function createSharedDispatcher(opts: SharedDispatcherOptions): SharedDispatcher;
170
237
  /**
171
- * Inject `sourceQueueItemId` into a settling tool call's arguments
172
- * when a pendingActionMap entry is registered for the call's target.
173
- * Currently only `create_thread_reply` settles a thread_message
174
- * dispatch; extend this set as new auto-injection rules are ratified.
238
+ * bug-53 boot-time fail-fast: assert host adapter has opted into
239
+ * pollBackstop wiring (transport_heartbeat periodic timer). Throws if
240
+ * `dispatcher.pollBackstop === undefined` UNLESS `TRANSPORT_HEARTBEAT_ENABLED=false`
241
+ * is set explicitly (opt-out path).
242
+ *
243
+ * Class: substrate-runtime-gap (sister to bug-49/50/51). Mission-75 §3.3
244
+ * substrate (PollBackstop heartbeat-second-timer) shipped at thread-472 with
245
+ * unit tests green, but the host integration was never written — both
246
+ * adapters call `createSharedDispatcher({...})` without supplying
247
+ * `opts.pollBackstop`, so the dispatcher's pollBackstop field stayed
248
+ * `undefined` and neither the poll-timer nor the heartbeat-timer ever
249
+ * scheduled. ZERO `transport_heartbeat` MCP tool calls fired in 96 minutes
250
+ * post Hub-restart (5127-line shim.log + 1789-event ndjson confirmed).
175
251
  *
176
- * Side effect: deletes the consumed map entry. Explicit
177
- * sourceQueueItemId in the args wins over the map (no rewrite).
252
+ * This assertion is a §6.4-equivalent gate: each host MUST call
253
+ * `assertHostWiringComplete(dispatcher)` post-startup so the bug-53 class
254
+ * cannot recur silently. Misconfiguration fails fast at boot, not invisibly
255
+ * after 96 minutes of clinical observability degradation.
178
256
  */
179
- export declare function injectQueueItemId(name: string, args: Record<string, unknown>, pendingActionMap: Map<string, string>): Record<string, unknown>;
180
- export declare function createSharedDispatcher(opts: SharedDispatcherOptions): SharedDispatcher;
257
+ export declare function assertHostWiringComplete(dispatcher: {
258
+ pollBackstop?: PollBackstop;
259
+ }, log?: (msg: string) => void): void;