macp-sdk-typescript 0.18.0 → 0.19.0

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/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to `macp-sdk-typescript` are documented here. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
5
5
  project uses [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.19.0](https://github.com/multiagentcoordinationprotocol/macp-sdk-typescript/compare/v0.18.0...v0.19.0) (2026-10-26)
8
+
9
+
10
+ ### Features
11
+
12
+ * capability-gated whatIfReplay and HISTORY_UNAVAILABLE (RFC-MACP-0012 §8.1) ([c5bc5cf](https://github.com/multiagentcoordinationprotocol/macp-sdk-typescript/commit/c5bc5cf6d8206c30f5d69f6fde44800e8d294fa6))
13
+ * **claude-agent-sdk:** Claude Agent SDK subagents reach a binding MACP decision (W3.5) ([573bf33](https://github.com/multiagentcoordinationprotocol/macp-sdk-typescript/commit/573bf335d433ad13bcb5668d1563b67494df4442))
14
+
7
15
  ## [0.18.0](https://github.com/multiagentcoordinationprotocol/macp-sdk-typescript/compare/v0.17.1...v0.18.0) (2026-10-25)
8
16
 
9
17
 
package/README.md CHANGED
@@ -72,7 +72,7 @@ client.close();
72
72
 
73
73
  The SDK uses a **three-layer** design:
74
74
 
75
- - **Low-level transport** (`MacpClient`): typed wrappers around every `MACPRuntimeService` RPC — `initialize`, `send`, `openStream`, `getSession`, `cancelSession`, `suspendSession`, `resumeSession`, `listSessions`, `getManifest`, `listModes`, `listRoots`, `listExtModes`, `registerExtMode`, `unregisterExtMode`, `promoteMode`, the policy RPCs (`register`/`unregister`/`get`/`listPolicies`), plus streaming watchers (`ModeRegistryWatcher`, `RootsWatcher`, `SignalWatcher`, `PolicyWatcher`, `SessionLifecycleWatcher`).
75
+ - **Low-level transport** (`MacpClient`): typed wrappers around every `MACPRuntimeService` RPC — `initialize`, `send`, `openStream`, `getSession`, `cancelSession`, `suspendSession`, `resumeSession`, `listSessions`, `getManifest`, `listModes`, `listRoots`, `listExtModes`, `registerExtMode`, `unregisterExtMode`, `promoteMode`, the policy RPCs (`register`/`unregister`/`get`/`listPolicies`, and `whatIfReplay` where the runtime advertises it), plus streaming watchers (`ModeRegistryWatcher`, `RootsWatcher`, `SignalWatcher`, `PolicyWatcher`, `SessionLifecycleWatcher`).
76
76
  - **High-level session helpers**: one class per coordination mode (`DecisionSession`, `ProposalSession`, `TaskSession`, `HandoffSession`, `QuorumSession`) — wraps `MacpClient`, builds envelopes, encodes payloads, and maintains a local state projection.
77
77
  - **Agent framework** (`src/agent/`): event-driven `Participant` with strategy-based handlers, bootstrap runner (`fromBootstrap`), gRPC/HTTP transports, and the optional cancel-callback HTTP server.
78
78
 
@@ -335,6 +335,17 @@ server via `fromBootstrap()`; for the manual path use
335
335
  See [`docs/api/cancel-callback.md`](docs/api/cancel-callback.md) and
336
336
  [`examples/cancel-callback.ts`](examples/cancel-callback.ts).
337
337
 
338
+ ## Framework Integrations
339
+
340
+ Framework adapters live under [`integrations/`](integrations/). Each is a separate npm package
341
+ with its own version and release tag.
342
+
343
+ | Framework | Package | |
344
+ | --- | --- | --- |
345
+ | LangGraph | [`@multiagentcoordinationprotocol/langgraph`](integrations/langgraph/) | `MacpConsensusNode`: a graph node whose participants evaluate and vote through a Decision or Quorum session and write the commitment into graph state |
346
+ | Claude Agent SDK | [`@multiagentcoordinationprotocol/claude-agent-sdk`](integrations/claude-agent-sdk/) | `claudeEvaluator` runs a Claude agent as a participant; `macpConsensusServer` gives a lead agent an `mcp__macp__consensus` tool whose subagents evaluate and vote, returning the commitment |
347
+ | OpenAI Agents SDK | planned | |
348
+
338
349
  ## Authentication
339
350
 
340
351
  ```typescript
package/dist/client.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as grpc from '@grpc/grpc-js';
2
2
  import { type AuthConfig } from './auth';
3
3
  import { ProtoRegistry } from './proto-registry';
4
- import type { Ack, AgentManifest, Envelope, InitializeResult, ModeDescriptor, PolicyDescriptor, SessionMetadata, Root } from './types';
4
+ import type { Ack, AgentManifest, Envelope, InitializeResult, ModeDescriptor, PolicyDescriptor, SessionMetadata, Root, WhatIfReplayResult } from './types';
5
5
  interface MacpClientOptions {
6
6
  address: string;
7
7
  /**
@@ -99,6 +99,10 @@ export declare class MacpClient {
99
99
  private readonly defaultDeadlineMs?;
100
100
  private readonly clientName;
101
101
  private readonly clientVersion;
102
+ /** The last {@link initialize} result; {@link whatIfReplay} reads its capabilities. */
103
+ private initializeResult?;
104
+ /** The runtime's capabilities from the last {@link initialize}; `undefined` before one. */
105
+ get serverCapabilities(): Record<string, unknown> | undefined;
102
106
  constructor(options: MacpClientOptions);
103
107
  private requireAuth;
104
108
  private metadata;
@@ -226,6 +230,25 @@ export declare class MacpClient {
226
230
  auth?: AuthConfig;
227
231
  deadlineMs?: number;
228
232
  }): Promise<PolicyDescriptor[]>;
233
+ /**
234
+ * Replay a session's accepted history under a candidate policy and report how
235
+ * the outcome would differ (RFC-MACP-0012 §8.1). Read-only and advisory: the
236
+ * session, its history and the policy registry are untouched, and the
237
+ * candidate is never registered.
238
+ *
239
+ * The RPC is optional, so this checks `capabilities.policyRegistry.whatIfReplay`
240
+ * from {@link initialize} first (calling it once if this client hasn't) and
241
+ * throws {@link MacpSdkError} without sending anything when the runtime
242
+ * doesn't advertise it. Runtime refusals arrive as {@link MacpTransportError}
243
+ * with `macpErrorCode` set: `SESSION_NOT_FOUND`, `FORBIDDEN` (authorized as
244
+ * {@link getSession}), `INVALID_POLICY_DEFINITION` (the candidate fails
245
+ * RegisterPolicy admission, or its mode is neither the session's nor `*`),
246
+ * `HISTORY_UNAVAILABLE` (history compacted), `INTERNAL_ERROR`.
247
+ */
248
+ whatIfReplay(sessionId: string, candidate: PolicyDescriptor, options?: {
249
+ auth?: AuthConfig;
250
+ deadlineMs?: number;
251
+ }): Promise<WhatIfReplayResult>;
229
252
  /**
230
253
  * Fetch a single page of sessions (proto ≥ 0.1.6). `pageSize: 0` (or absent)
231
254
  * lets the server choose the page size; the server MAY cap it. Callers MUST
package/dist/client.js CHANGED
@@ -276,6 +276,12 @@ class MacpClient {
276
276
  defaultDeadlineMs;
277
277
  clientName;
278
278
  clientVersion;
279
+ /** The last {@link initialize} result; {@link whatIfReplay} reads its capabilities. */
280
+ initializeResult;
281
+ /** The runtime's capabilities from the last {@link initialize}; `undefined` before one. */
282
+ get serverCapabilities() {
283
+ return this.initializeResult?.capabilities;
284
+ }
279
285
  constructor(options) {
280
286
  this.auth = options.auth;
281
287
  this.secure = options.secure ?? true;
@@ -360,7 +366,7 @@ class MacpClient {
360
366
  });
361
367
  }
362
368
  async initialize(deadlineMs) {
363
- return this.unary('Initialize', {
369
+ const result = await this.unary('Initialize', {
364
370
  supportedProtocolVersions: ['1.0'],
365
371
  clientInfo: {
366
372
  name: this.clientName,
@@ -380,6 +386,8 @@ class MacpClient {
380
386
  experimental: { features: {} },
381
387
  },
382
388
  }, undefined, deadlineMs);
389
+ this.initializeResult = result;
390
+ return result;
383
391
  }
384
392
  async send(envelope, options) {
385
393
  const auth = this.requireAuth(options?.auth);
@@ -513,6 +521,40 @@ class MacpClient {
513
521
  const res = await this.unary('ListPolicies', { mode: mode || '' }, auth, options?.deadlineMs);
514
522
  return res.descriptors || [];
515
523
  }
524
+ /**
525
+ * Replay a session's accepted history under a candidate policy and report how
526
+ * the outcome would differ (RFC-MACP-0012 §8.1). Read-only and advisory: the
527
+ * session, its history and the policy registry are untouched, and the
528
+ * candidate is never registered.
529
+ *
530
+ * The RPC is optional, so this checks `capabilities.policyRegistry.whatIfReplay`
531
+ * from {@link initialize} first (calling it once if this client hasn't) and
532
+ * throws {@link MacpSdkError} without sending anything when the runtime
533
+ * doesn't advertise it. Runtime refusals arrive as {@link MacpTransportError}
534
+ * with `macpErrorCode` set: `SESSION_NOT_FOUND`, `FORBIDDEN` (authorized as
535
+ * {@link getSession}), `INVALID_POLICY_DEFINITION` (the candidate fails
536
+ * RegisterPolicy admission, or its mode is neither the session's nor `*`),
537
+ * `HISTORY_UNAVAILABLE` (history compacted), `INTERNAL_ERROR`.
538
+ */
539
+ async whatIfReplay(sessionId, candidate, options) {
540
+ const auth = this.requireAuth(options?.auth);
541
+ const capabilities = this.serverCapabilities ?? (await this.initialize(options?.deadlineMs)).capabilities;
542
+ const policyRegistry = capabilities?.policyRegistry;
543
+ if (!policyRegistry?.whatIfReplay) {
544
+ throw new errors_1.MacpSdkError('this runtime does not advertise capabilities.policyRegistry.whatIfReplay; ' +
545
+ 'WhatIfReplay is optional and a client MUST NOT call it otherwise (RFC-MACP-0012 §8.1)');
546
+ }
547
+ const res = await this.unary('WhatIfReplay', { sessionId, candidate }, auth, options?.deadlineMs);
548
+ // proto3 `optional` decodes with a synthetic oneof discriminator; an unset
549
+ // first_divergence is absent, never "0" (index 0 is the SessionStart).
550
+ const result = {
551
+ ...res,
552
+ denials: res.denials ?? [],
553
+ entries: res.entries ?? [],
554
+ };
555
+ delete result._firstDivergence;
556
+ return result;
557
+ }
516
558
  /**
517
559
  * Fetch a single page of sessions (proto ≥ 0.1.6). `pageSize: 0` (or absent)
518
560
  * lets the server choose the page size; the server MAY cap it. Callers MUST
@@ -37,6 +37,11 @@ export declare const INVALID_REQUEST = "INVALID_REQUEST";
37
37
  export declare const STREAM_LAGGED = "STREAM_LAGGED";
38
38
  /** GetManifest for an agent this runtime does not host — NOT_FOUND. */
39
39
  export declare const AGENT_NOT_FOUND = "AGENT_NOT_FOUND";
40
+ /**
41
+ * WhatIfReplay on a session whose full accepted history the runtime no longer
42
+ * holds (e.g. compacted when it ended) — FAILED_PRECONDITION. RFC-MACP-0012 §8.1.
43
+ */
44
+ export declare const HISTORY_UNAVAILABLE = "HISTORY_UNAVAILABLE";
40
45
  export declare const DENY_VETO = "veto";
41
46
  export declare const DENY_VETO_HOLD = "veto_hold";
42
47
  export declare const DENY_QUORUM_NOT_MET = "quorum_not_met";
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.KNOWN_DENY_CODES = exports.DENY_UNSPECIFIED = exports.DENY_INVALID_RULES = exports.DENY_UNSUPPORTED_SCHEMA_VERSION = exports.DENY_REASSIGNMENT_NOT_ALLOWED = exports.DENY_OUTPUT_REQUIRED = exports.DENY_CRITERION_NOT_MET = exports.DENY_DECLINE_NOT_BACKED = exports.DENY_DECLINE_OVER_APPROVAL = exports.DENY_NO_VOTES = exports.DENY_EVALUATION_REQUIRED = exports.DENY_CONFIDENCE_BELOW_MINIMUM = exports.DENY_THRESHOLD_NOT_MET = exports.DENY_QUORUM_NOT_MET = exports.DENY_VETO_HOLD = exports.DENY_VETO = exports.AGENT_NOT_FOUND = exports.STREAM_LAGGED = exports.INVALID_REQUEST = exports.REGISTRY_READ_ONLY = exports.INVALID_POLICY_DEFINITION = exports.UNKNOWN_POLICY_VERSION = exports.INVALID_SESSION_ID = exports.POLICY_DENIED = exports.INTERNAL_ERROR = exports.RATE_LIMITED = exports.PAYLOAD_TOO_LARGE = exports.DUPLICATE_MESSAGE = exports.UNAUTHENTICATED = exports.FORBIDDEN = exports.MODE_NOT_SUPPORTED = exports.SESSION_NOT_OPEN = exports.SESSION_NOT_FOUND = exports.SESSION_ALREADY_EXISTS = exports.INVALID_ENVELOPE = exports.UNSUPPORTED_PROTOCOL_VERSION = exports.STANDARD_MODES = exports.MODE_MULTI_ROUND = exports.MODE_QUORUM = exports.MODE_HANDOFF = exports.MODE_TASK = exports.MODE_PROPOSAL = exports.MODE_DECISION = exports.DEFAULT_POLICY_VERSION = exports.DEFAULT_CONFIGURATION_VERSION = exports.DEFAULT_MODE_VERSION = exports.MACP_VERSION = void 0;
3
+ exports.KNOWN_DENY_CODES = exports.DENY_UNSPECIFIED = exports.DENY_INVALID_RULES = exports.DENY_UNSUPPORTED_SCHEMA_VERSION = exports.DENY_REASSIGNMENT_NOT_ALLOWED = exports.DENY_OUTPUT_REQUIRED = exports.DENY_CRITERION_NOT_MET = exports.DENY_DECLINE_NOT_BACKED = exports.DENY_DECLINE_OVER_APPROVAL = exports.DENY_NO_VOTES = exports.DENY_EVALUATION_REQUIRED = exports.DENY_CONFIDENCE_BELOW_MINIMUM = exports.DENY_THRESHOLD_NOT_MET = exports.DENY_QUORUM_NOT_MET = exports.DENY_VETO_HOLD = exports.DENY_VETO = exports.HISTORY_UNAVAILABLE = exports.AGENT_NOT_FOUND = exports.STREAM_LAGGED = exports.INVALID_REQUEST = exports.REGISTRY_READ_ONLY = exports.INVALID_POLICY_DEFINITION = exports.UNKNOWN_POLICY_VERSION = exports.INVALID_SESSION_ID = exports.POLICY_DENIED = exports.INTERNAL_ERROR = exports.RATE_LIMITED = exports.PAYLOAD_TOO_LARGE = exports.DUPLICATE_MESSAGE = exports.UNAUTHENTICATED = exports.FORBIDDEN = exports.MODE_NOT_SUPPORTED = exports.SESSION_NOT_OPEN = exports.SESSION_NOT_FOUND = exports.SESSION_ALREADY_EXISTS = exports.INVALID_ENVELOPE = exports.UNSUPPORTED_PROTOCOL_VERSION = exports.STANDARD_MODES = exports.MODE_MULTI_ROUND = exports.MODE_QUORUM = exports.MODE_HANDOFF = exports.MODE_TASK = exports.MODE_PROPOSAL = exports.MODE_DECISION = exports.DEFAULT_POLICY_VERSION = exports.DEFAULT_CONFIGURATION_VERSION = exports.DEFAULT_MODE_VERSION = exports.MACP_VERSION = void 0;
4
4
  exports.MACP_VERSION = '1.0';
5
5
  exports.DEFAULT_MODE_VERSION = '1.0.0';
6
6
  exports.DEFAULT_CONFIGURATION_VERSION = 'config.default';
@@ -44,6 +44,11 @@ exports.INVALID_REQUEST = 'INVALID_REQUEST';
44
44
  exports.STREAM_LAGGED = 'STREAM_LAGGED';
45
45
  /** GetManifest for an agent this runtime does not host — NOT_FOUND. */
46
46
  exports.AGENT_NOT_FOUND = 'AGENT_NOT_FOUND';
47
+ /**
48
+ * WhatIfReplay on a session whose full accepted history the runtime no longer
49
+ * holds (e.g. compacted when it ended) — FAILED_PRECONDITION. RFC-MACP-0012 §8.1.
50
+ */
51
+ exports.HISTORY_UNAVAILABLE = 'HISTORY_UNAVAILABLE';
47
52
  // Structured POLICY_DENIED denial codes (`PolicyDenial.code`, runtime ≥ 0.9.0;
48
53
  // RFC-MACP-0012 §6.2). Open set — names match python-sdk's exports.
49
54
  exports.DENY_VETO = 'veto';
package/dist/types.d.ts CHANGED
@@ -100,6 +100,65 @@ export interface PolicyRegistryCapability {
100
100
  * admission, not this list, is authoritative. Runtime ≥ 0.9.0.
101
101
  */
102
102
  ruleExtensions?: string[];
103
+ /**
104
+ * The runtime implements the optional, read-only `WhatIfReplay` RPC
105
+ * (RFC-MACP-0012 §8.1); {@link MacpClient.whatIfReplay} refuses to call it
106
+ * otherwise. Proto ≥ 0.1.12.
107
+ */
108
+ whatIfReplay?: boolean;
109
+ }
110
+ /** How one replay handled one history entry (`macp.v1.WhatIfEntryOutcome`). */
111
+ export interface WhatIfEntryOutcome {
112
+ kind: 'KIND_UNSPECIFIED' | 'KIND_APPLIED' | 'KIND_NOT_OPEN' | 'KIND_REFUSED' | 'KIND_NO_SESSION';
113
+ /** Session state after the entry, for `KIND_APPLIED`. */
114
+ state: string;
115
+ /** MACP error code, for `KIND_REFUSED`. */
116
+ errorCode: string;
117
+ /** For a `POLICY_DENIED` refusal, the §6.2 detail JSON; see {@link parseErrorDetails}. */
118
+ details: Buffer;
119
+ }
120
+ /** One accepted-history entry as both replays handled it. `historyIndex` is 0-based; the SessionStart is 0. */
121
+ export interface WhatIfEntry {
122
+ historyIndex: string;
123
+ messageId: string;
124
+ messageType: string;
125
+ recorded: WhatIfEntryOutcome | null;
126
+ candidate: WhatIfEntryOutcome | null;
127
+ }
128
+ /** One replay's final outcome (`macp.v1.WhatIfOutcome`). */
129
+ export interface WhatIfOutcome {
130
+ /** `SESSION_STATE_UNSPECIFIED` when the candidate refused the SessionStart. */
131
+ state: string;
132
+ /** The resolving Commitment's payload bytes; empty if unresolved. */
133
+ resolution: Buffer;
134
+ resolvedByHistoryIndex: string;
135
+ /** Empty if unresolved. */
136
+ resolvedByMessageId: string;
137
+ resolvedByMessageType: string;
138
+ }
139
+ /** A `POLICY_DENIED` the candidate produced; `details` as {@link WhatIfEntryOutcome.details}. */
140
+ export interface WhatIfDenial {
141
+ historyIndex: string;
142
+ messageId: string;
143
+ details: Buffer;
144
+ }
145
+ /**
146
+ * `macp.v1.WhatIfReplayResponse`: a session's accepted history replayed under
147
+ * its bound policy (`recorded`) and under a candidate. Advisory, never binding.
148
+ * uint64 fields are decimal strings, as elsewhere in this client.
149
+ */
150
+ export interface WhatIfReplayResult {
151
+ candidatePolicyId: string;
152
+ /** The policy the session is bound to (`policy.default` if none was named). */
153
+ recordedPolicyId: string;
154
+ recorded: WhatIfOutcome | null;
155
+ candidate: WhatIfOutcome | null;
156
+ /** First history index the two replays handled differently; absent when they agree throughout. */
157
+ firstDivergence?: string;
158
+ /** Every POLICY_DENIED the candidate produced, in history order. */
159
+ denials: WhatIfDenial[];
160
+ /** One entry per accepted-history entry, in history order. */
161
+ entries: WhatIfEntry[];
103
162
  }
104
163
  export interface InitializeResult {
105
164
  selectedProtocolVersion: string;
package/dist/version.d.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * Kept in sync with package.json by release-please (see the
5
5
  * `x-release-please-version` annotation).
6
6
  */
7
- export declare const VERSION = "0.18.0";
7
+ export declare const VERSION = "0.19.0";
package/dist/version.js CHANGED
@@ -7,4 +7,4 @@ exports.VERSION = void 0;
7
7
  * Kept in sync with package.json by release-please (see the
8
8
  * `x-release-please-version` annotation).
9
9
  */
10
- exports.VERSION = '0.18.0'; // x-release-please-version
10
+ exports.VERSION = '0.19.0'; // x-release-please-version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "macp-sdk-typescript",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "TypeScript SDK for the MACP Rust runtime",
5
5
  "license": "Apache-2.0",
6
6
  "type": "commonjs",
@@ -60,7 +60,7 @@
60
60
  "dependencies": {
61
61
  "@grpc/grpc-js": "^1.14.3",
62
62
  "@grpc/proto-loader": "^0.8.0",
63
- "@multiagentcoordinationprotocol/proto": "^0.1.11",
63
+ "@multiagentcoordinationprotocol/proto": "^0.1.12",
64
64
  "@noble/curves": "^1.9.7",
65
65
  "@noble/hashes": "^1.8.0",
66
66
  "protobufjs": "^8.6.5"