macp-sdk-typescript 0.2.0 → 0.3.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +124 -1
  2. package/README.md +99 -3
  3. package/dist/agent/cancel-callback.d.ts +23 -0
  4. package/dist/agent/cancel-callback.js +108 -0
  5. package/dist/agent/index.d.ts +1 -0
  6. package/dist/agent/index.js +1 -0
  7. package/dist/agent/participant.d.ts +58 -0
  8. package/dist/agent/participant.js +143 -45
  9. package/dist/agent/runner.d.ts +34 -1
  10. package/dist/agent/runner.js +53 -0
  11. package/dist/agent/strategies.d.ts +2 -0
  12. package/dist/agent/strategies.js +8 -0
  13. package/dist/agent/transports.js +5 -0
  14. package/dist/base-session.d.ts +64 -0
  15. package/dist/base-session.js +112 -0
  16. package/dist/client.d.ts +25 -0
  17. package/dist/client.js +100 -10
  18. package/dist/constants.d.ts +21 -16
  19. package/dist/constants.js +24 -17
  20. package/dist/decision.d.ts +2 -1
  21. package/dist/decision.js +2 -1
  22. package/dist/envelope.d.ts +25 -3
  23. package/dist/envelope.js +42 -11
  24. package/dist/errors.d.ts +17 -4
  25. package/dist/errors.js +19 -10
  26. package/dist/handoff.d.ts +2 -9
  27. package/dist/handoff.js +2 -17
  28. package/dist/index.d.ts +3 -1
  29. package/dist/index.js +10 -2
  30. package/dist/logging.d.ts +21 -0
  31. package/dist/logging.js +64 -0
  32. package/dist/policy.d.ts +47 -42
  33. package/dist/policy.js +6 -6
  34. package/dist/projections/base.d.ts +20 -0
  35. package/dist/projections/base.js +37 -0
  36. package/dist/projections.d.ts +1 -0
  37. package/dist/projections.js +1 -0
  38. package/dist/proposal.d.ts +2 -1
  39. package/dist/proposal.js +2 -1
  40. package/dist/quorum.d.ts +2 -1
  41. package/dist/quorum.js +2 -1
  42. package/dist/task.d.ts +6 -5
  43. package/dist/task.js +6 -5
  44. package/dist/types.d.ts +11 -2
  45. package/dist/watchers.d.ts +23 -1
  46. package/dist/watchers.js +59 -1
  47. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -4,15 +4,138 @@ 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
- ## [Unreleased]
7
+ ## [0.3.0] - 2026-04-21
8
+
9
+ Parity release — brings TypeScript SDK to full feature parity with
10
+ `macp-sdk-python` 0.3.0. Plan: `plans/sdk-parity-plan.md`.
11
+
12
+ ### Added
13
+
14
+ - **Cancel-callback server** (Gap B, RFC-0001 §7.2 Option A):
15
+ `startCancelCallbackServer({ host, port, path, onCancel })` returns a
16
+ handle backed by Node's `http` module; `Participant` starts the server
17
+ automatically when `ParticipantConfig.cancelCallback` is set and closes
18
+ it on `stop()`. `fromBootstrap()` wires the new `cancel_callback`
19
+ field in the bootstrap JSON. Exports:
20
+ `startCancelCallbackServer`, `CancelCallbackServer`, `CancelHandler`.
21
+ - **Function-wrapped voting and commitment strategies** (Gap C):
22
+ `functionVoter(shouldVote, decideVote)` and
23
+ `functionCommitter(shouldCommit, decideCommitment)` in
24
+ `src/agent/strategies.ts` — the low-friction way to plug a custom rule
25
+ into a `Participant` without a class.
26
+ - **Standalone signal and progress builders** (Gap D):
27
+ `buildSignalPayload(input)` and `buildProgressPayload(input)` in
28
+ `src/envelope.ts`. `MacpClient.sendSignal` / `sendProgress` now use
29
+ the shared builders internally.
30
+ - **`serializeMessage(msg)` helper** (Gap N) — parity with
31
+ `python-sdk envelope.serialize_message`; dispatches to
32
+ `serializeBinary()` / `toBinary()` / `finish()` on the passed
33
+ protobuf message.
34
+ - **Structured logger** (Gap G): `src/logging.ts` exports `logger` with
35
+ `error`/`warn`/`info`/`debug` level methods and `configureLogging({ level, sink })`.
36
+ Reads `MACP_LOG_LEVEL` on module init (default `warn`). The two
37
+ remaining `console.*` callsites in `src/agent/participant.ts` and
38
+ `src/handoff.ts` now route through the structured logger.
39
+ - **`AckFailure` shape** (Gap I): structured NACK record exported from
40
+ `src/errors.ts`. Populated on `MacpAckError.failure` from both
41
+ `ack.error.details` and gRPC trailing metadata.
42
+ - **`BaseSession` / `BaseProjection`** (Gap J): abstract extension
43
+ points exported from `src/base-session.ts` and `src/projections/base.ts`
44
+ for custom mode helpers (modes registered via `registerExtMode`).
45
+ Mirrors `python-sdk`'s `BaseSession` / `BaseProjection`.
46
+ - **Named policy rule interfaces** (Gap K): `VotingRules`,
47
+ `ObjectionHandlingRules`, `EvaluationRules`, `CommitmentRules`,
48
+ `QuorumThreshold`, `AbstentionRules`, `ProposalAcceptanceRules`,
49
+ `CounterProposalRules`, `RejectionRules`, `TaskAssignmentRules`,
50
+ `TaskCompletionRules`, `HandoffAcceptanceRules` now exported as
51
+ first-class interfaces matching `macp-sdk-python` exports.
52
+ - **`STANDARD_MODES` tuple** (Gap L) in `src/constants.ts`.
53
+ - **Parity examples** (Gap M): `examples/policy-registration.ts`,
54
+ `examples/agent-policy-aware.ts`, `examples/direct-agent-auth-initiator.ts`,
55
+ `examples/direct-agent-auth-observer.ts`.
56
+
57
+ ### Changed
58
+
59
+ - **Error-code constants renamed** (Gap F, breaking): dropped the
60
+ `ERR_` prefix so TS constants match the on-the-wire strings and the
61
+ `macp-sdk-python` exports. Rename table —
62
+ `ERR_UNSUPPORTED_PROTOCOL_VERSION` → `UNSUPPORTED_PROTOCOL_VERSION`,
63
+ `ERR_INVALID_ENVELOPE` → `INVALID_ENVELOPE`,
64
+ `ERR_SESSION_NOT_FOUND` → `SESSION_NOT_FOUND`,
65
+ `ERR_SESSION_NOT_OPEN` → `SESSION_NOT_OPEN`,
66
+ `ERR_SESSION_ALREADY_EXISTS` → `SESSION_ALREADY_EXISTS`,
67
+ `ERR_MODE_NOT_SUPPORTED` → `MODE_NOT_SUPPORTED`,
68
+ `ERR_FORBIDDEN` → `FORBIDDEN`,
69
+ `ERR_UNAUTHENTICATED` → `UNAUTHENTICATED`,
70
+ `ERR_DUPLICATE_MESSAGE` → `DUPLICATE_MESSAGE`,
71
+ `ERR_PAYLOAD_TOO_LARGE` → `PAYLOAD_TOO_LARGE`,
72
+ `ERR_RATE_LIMITED` → `RATE_LIMITED`,
73
+ `ERR_INTERNAL_ERROR` → `INTERNAL_ERROR`,
74
+ `ERR_POLICY_DENIED` → `POLICY_DENIED`,
75
+ `ERR_INVALID_SESSION_ID` → `INVALID_SESSION_ID`,
76
+ `ERR_UNKNOWN_POLICY_VERSION` → `UNKNOWN_POLICY_VERSION`,
77
+ `ERR_INVALID_POLICY_DEFINITION` → `INVALID_POLICY_DEFINITION`.
78
+ - `MacpClient.clientVersion` default now `0.3.0`.
79
+
80
+ ### Removed
81
+
82
+ - **`HandoffSession.sendContext()`** (Gap A, breaking): the deprecated
83
+ alias (warning first emitted in 0.2.3) has been removed. Use
84
+ `HandoffSession.addContext()`.
85
+ - **`MacpAckError.reasons` getter** (breaking): use
86
+ `MacpAckError.failure.reasons` instead. `.failure` is the canonical
87
+ structured NACK record and matches `macp-sdk-python`'s
88
+ `MacpAckError.failure`.
89
+ - **Mode-prefixed policy rule type aliases** (breaking): the
90
+ `CommitmentRulesInput`, `DecisionVotingRules`,
91
+ `DecisionObjectionHandling`, `DecisionEvaluationRules`, and
92
+ `DecisionCommitmentRules` type aliases have been removed. Use the
93
+ unprefixed names (`CommitmentRules`, `VotingRules`,
94
+ `ObjectionHandlingRules`, `EvaluationRules`) introduced in Gap K.
95
+
96
+ ## [0.2.3] - 2026-04-21
8
97
 
9
98
  ### Added
99
+ - `MacpStream.sendSubscribe(sessionId, afterSequence?)` — subscribe-only stream
100
+ frame (RFC-MACP-0006-A1). The runtime replays accepted envelopes from the
101
+ cursor before switching to live broadcast, so non-initiator agents observe
102
+ `SessionStart` and earlier mode envelopes regardless of join order.
103
+ - `GrpcTransportAdapter` now sends a subscribe frame automatically on start so
104
+ `Participant`-based agents pick up history without bespoke wiring.
105
+ - Unit coverage for `MacpStream.sendSubscribe` (default cursor, custom cursor,
106
+ closed-stream rejection, write-error propagation, sequential resubscribe) and
107
+ `GrpcTransportAdapter` (subscribe ordering, empty-stream subscribe, auth
108
+ pass-through to `openStream`).
109
+ - Integration tests for late-subscriber replay and future-cursor skip
110
+ (`tests/integration/runtime.test.ts`).
111
+ - `InitiatorConfig.sessionStart` now accepts `contextId` and `extensions`, and
112
+ `Participant.emitInitiatorEnvelopes()` forwards both to the mode-session
113
+ `start()` call (SDK-TS-1). `fromBootstrap()` decodes `context_id` plus a
114
+ JSON-native `extensions` map from the bootstrap file — each value is
115
+ serialised as UTF-8 JSON into the `Record<string, Buffer>` shape the
116
+ envelope requires; pre-encoded `Buffer` / `Uint8Array` values pass through
117
+ unchanged.
118
+ - Documented `MacpClient.listSessions()` (parity with the python-sdk SDK-PY-2
119
+ gap) and `SessionLifecycleWatcher` (parity with python-sdk SDK-PY-3). Both
120
+ were already implemented — this release adds the API reference, a
121
+ `docs/guides/streaming.md` section, unit coverage for `listSessions`, and
122
+ integration tests that exercise enumeration + a `CREATED` lifecycle event
123
+ round-trip against a live runtime.
10
124
  - Warn-once migration hint when the deprecated `HandoffSession.sendContext()`
11
125
  alias is invoked. Scheduled for removal in `0.4.0`; use `addContext()`.
12
126
  - `docs/api/sessions.md` now documents the identity-guard contract.
13
127
  - `docs/guides/architecture.md` rewritten to reflect the three-layer design
14
128
  (transport / session helpers / agent framework).
15
129
 
130
+ ### Changed
131
+ - Integration tests updated to match the proto field renames that landed in
132
+ `@multiagentcoordinationprotocol/proto@0.1.x`: `Evaluation.analysis` →
133
+ `reason`, `Proposal.description` → `summary`, `TaskRequest.assignee` →
134
+ `requestedAssignee` (Task accept/update/complete/fail/reject now carry an
135
+ `assignee` field), `TaskUpdate.progress` is required, `HandoffContext.data`
136
+ → `context` (+ `contentType`), `HandoffAccept.acceptedBy` and
137
+ `HandoffDecline.declinedBy` are now required.
138
+
16
139
  ### Deprecated
17
140
  - `HandoffSession.sendContext()` remains available as an alias but emits a
18
141
  one-shot `console.warn`. Use `HandoffSession.addContext()` instead.
package/README.md CHANGED
@@ -74,6 +74,21 @@ Every session class follows the same pattern:
74
74
  4. Call `commit()` to finalize
75
75
  5. Read `session.projection` for local state
76
76
 
77
+ ### Session Start Options
78
+
79
+ All `start()` methods accept `contextId` and `extensions` for session-level metadata:
80
+
81
+ ```typescript
82
+ await session.start({
83
+ intent: 'pick a deployment strategy',
84
+ participants: ['alice', 'bob'],
85
+ ttlMs: 60_000,
86
+ contextId: 'ctx-abc', // optional opaque context reference
87
+ extensions: { 'x-trace': Buffer.from('tid') }, // optional typed extension buffers
88
+ roots: [{ uri: 'file:///workspace', name: 'repo' }],
89
+ });
90
+ ```
91
+
77
92
  ## Coordination Modes
78
93
 
79
94
  ### Decision Mode
@@ -126,10 +141,10 @@ import { TaskSession } from 'macp-sdk-typescript';
126
141
 
127
142
  const session = new TaskSession(client);
128
143
  await session.start({ intent: '...', participants: ['worker'], ttlMs: 120_000 });
129
- await session.request({ taskId: 't1', title: 'Build feature', instructions: '...' });
144
+ await session.requestTask({ taskId: 't1', title: 'Build feature', instructions: '...' });
130
145
  await session.acceptTask({ taskId: 't1', assignee: 'worker' });
131
- await session.update({ taskId: 't1', status: 'working', progress: 0.5, message: 'halfway' });
132
- await session.complete({ taskId: 't1', assignee: 'worker', summary: 'done' });
146
+ await session.updateTask({ taskId: 't1', status: 'working', progress: 0.5, message: 'halfway' });
147
+ await session.completeTask({ taskId: 't1', assignee: 'worker', summary: 'done' });
133
148
  await session.commit({ action: 'task.completed', authorityScope: 'lead', reason: '...' });
134
149
 
135
150
  // Projection queries
@@ -177,6 +192,76 @@ session.projection.remainingVotesNeeded('r1'); // number
177
192
  session.projection.votedSenders('r1'); // string[]
178
193
  ```
179
194
 
195
+ ## Agent Framework
196
+
197
+ The `agent` module provides event-driven abstractions for building MACP participants.
198
+
199
+ ### Participant
200
+
201
+ `Participant` wraps a session, projection, and transport into a single event-driven handler:
202
+
203
+ ```typescript
204
+ import { agent } from 'macp-sdk-typescript';
205
+
206
+ const participant = new agent.Participant({
207
+ participantId: 'evaluator',
208
+ sessionId: 'sid-123',
209
+ mode: 'macp.mode.decision.v1',
210
+ client,
211
+ transport: new agent.GrpcTransportAdapter(client, 'sid-123', auth),
212
+ });
213
+
214
+ participant
215
+ .on('Proposal', async (msg, ctx) => {
216
+ await ctx.actions.evaluate({
217
+ proposalId: msg.payload.proposalId,
218
+ recommendation: 'APPROVE',
219
+ confidence: 0.95,
220
+ });
221
+ })
222
+ .onTerminal(async (result) => {
223
+ console.log('session ended:', result.reason);
224
+ });
225
+
226
+ await participant.run();
227
+ ```
228
+
229
+ ### Bootstrap Runner
230
+
231
+ `fromBootstrap()` creates a fully-wired `Participant` from a JSON bootstrap file (typically provided by the runtime orchestrator):
232
+
233
+ ```typescript
234
+ import { agent } from 'macp-sdk-typescript';
235
+
236
+ // Reads from path argument or MACP_BOOTSTRAP_FILE env var
237
+ const participant = agent.fromBootstrap('./bootstrap.json');
238
+ participant.on('Proposal', handler);
239
+ await participant.run();
240
+ ```
241
+
242
+ Bootstrap files can include an `initiator` section for participants that start the session:
243
+
244
+ ```json
245
+ {
246
+ "session_id": "sid-123",
247
+ "participant_id": "coordinator",
248
+ "mode": "macp.mode.decision.v1",
249
+ "runtime_address": "localhost:50051",
250
+ "initiator": {
251
+ "session_start": {
252
+ "intent": "pick deployment strategy",
253
+ "participants": ["coordinator", "evaluator"],
254
+ "ttl_ms": 60000,
255
+ "roots": [{ "uri": "file:///workspace" }]
256
+ },
257
+ "kickoff": {
258
+ "message_type": "Proposal",
259
+ "payload": { "proposalId": "p1", "option": "canary" }
260
+ }
261
+ }
262
+ }
263
+ ```
264
+
180
265
  ## Authentication
181
266
 
182
267
  ```typescript
@@ -234,6 +319,17 @@ for await (const envelope of stream.responses()) {
234
319
  stream.close();
235
320
  ```
236
321
 
322
+ To attach to a session that is already in flight and receive accepted history before live broadcast (RFC-MACP-0006 §3.2 passive subscribe):
323
+
324
+ ```typescript
325
+ const stream = client.openStream({ auth });
326
+ await stream.sendSubscribe(sessionId); // full replay then live
327
+ // or, after a reconnect:
328
+ await stream.sendSubscribe(sessionId, lastSeq); // resume from cursor
329
+ ```
330
+
331
+ The agent framework's `GrpcTransportAdapter` calls this for you on start, so non-initiator agents see `SessionStart` regardless of join order.
332
+
237
333
  ### Registry & Root Watchers
238
334
 
239
335
  ```typescript
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Cancel-callback HTTP endpoint — RFC-0001 §7.2 Option A.
3
+ *
4
+ * Parity with python-sdk's `macp_sdk.agent.cancel_callback`. The
5
+ * examples-service's `BootstrapPayload.cancel_callback` field asks each
6
+ * agent to listen on `http://host:port{path}` for a `POST` whose JSON
7
+ * body is `{"runId": ..., "reason": ...}`. Receipt of the POST should
8
+ * stop the participant cleanly — typically by calling `participant.stop()`.
9
+ */
10
+ export type CancelHandler = (runId: string, reason: string) => void | Promise<void>;
11
+ export interface CancelCallbackServerOptions {
12
+ host: string;
13
+ port: number;
14
+ path: string;
15
+ onCancel: CancelHandler;
16
+ }
17
+ export interface CancelCallbackServer {
18
+ readonly host: string;
19
+ readonly port: number;
20
+ readonly path: string;
21
+ close(): Promise<void>;
22
+ }
23
+ export declare function startCancelCallbackServer(options: CancelCallbackServerOptions): Promise<CancelCallbackServer>;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.startCancelCallbackServer = startCancelCallbackServer;
37
+ const http = __importStar(require("node:http"));
38
+ const logging_1 = require("../logging");
39
+ function normalisePath(path) {
40
+ return path.startsWith('/') ? path : `/${path}`;
41
+ }
42
+ async function readBody(req) {
43
+ return new Promise((resolve, reject) => {
44
+ const chunks = [];
45
+ req.on('data', (chunk) => chunks.push(chunk));
46
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
47
+ req.on('error', reject);
48
+ });
49
+ }
50
+ function startCancelCallbackServer(options) {
51
+ const path = normalisePath(options.path);
52
+ return new Promise((resolve, reject) => {
53
+ const server = http.createServer(async (req, res) => {
54
+ if (req.method !== 'POST' || req.url !== path) {
55
+ res.statusCode = 404;
56
+ res.end();
57
+ return;
58
+ }
59
+ let body = {};
60
+ try {
61
+ const raw = await readBody(req);
62
+ if (raw)
63
+ body = JSON.parse(raw);
64
+ }
65
+ catch {
66
+ body = {};
67
+ }
68
+ const runId = String(body.runId ?? body.run_id ?? '');
69
+ const reason = String(body.reason ?? '');
70
+ logging_1.logger.info('cancel_callback invoked', { runId, reason });
71
+ try {
72
+ await options.onCancel(runId, reason);
73
+ }
74
+ catch (err) {
75
+ logging_1.logger.error('cancel_callback handler raised', err);
76
+ res.statusCode = 500;
77
+ res.end();
78
+ return;
79
+ }
80
+ res.statusCode = 202;
81
+ res.setHeader('Content-Type', 'application/json');
82
+ res.end('{"ok":true}');
83
+ });
84
+ server.once('error', reject);
85
+ server.listen(options.port, options.host, () => {
86
+ server.removeListener('error', reject);
87
+ const addr = server.address();
88
+ const boundHost = addr.address;
89
+ const boundPort = addr.port;
90
+ logging_1.logger.debug(`cancel_callback listening on http://${boundHost}:${boundPort}${path}`);
91
+ let closing = false;
92
+ const handle = {
93
+ host: boundHost,
94
+ port: boundPort,
95
+ path,
96
+ close() {
97
+ if (closing)
98
+ return Promise.resolve();
99
+ closing = true;
100
+ return new Promise((res, rej) => {
101
+ server.close((err) => (err ? rej(err) : res()));
102
+ });
103
+ },
104
+ };
105
+ resolve(handle);
106
+ });
107
+ });
108
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './types';
2
+ export * from './cancel-callback';
2
3
  export * from './dispatcher';
3
4
  export * from './participant';
4
5
  export * from './strategies';
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.HttpTransportAdapter = exports.GrpcTransportAdapter = void 0;
18
18
  __exportStar(require("./types"), exports);
19
+ __exportStar(require("./cancel-callback"), exports);
19
20
  __exportStar(require("./dispatcher"), exports);
20
21
  __exportStar(require("./participant"), exports);
21
22
  __exportStar(require("./strategies"), exports);
@@ -1,7 +1,27 @@
1
1
  import type { AuthConfig } from '../auth';
2
2
  import type { MacpClient } from '../client';
3
+ import type { Envelope } from '../types';
4
+ import { type CancelCallbackServer } from './cancel-callback';
3
5
  import { type TransportAdapter } from './transports';
4
6
  import type { MessageHandler, PhaseChangeHandler, ProjectionLike, SessionActions, TerminalHandler } from './types';
7
+ export interface InitiatorConfig {
8
+ sessionStart: {
9
+ intent: string;
10
+ participants: string[];
11
+ ttlMs: number;
12
+ contextId?: string;
13
+ extensions?: Record<string, Buffer>;
14
+ context?: Record<string, unknown>;
15
+ roots?: Array<{
16
+ uri: string;
17
+ name?: string;
18
+ }>;
19
+ };
20
+ kickoff?: {
21
+ messageType: string;
22
+ payload: Record<string, unknown>;
23
+ };
24
+ }
5
25
  export interface ParticipantConfig {
6
26
  participantId: string;
7
27
  sessionId: string;
@@ -13,6 +33,18 @@ export interface ParticipantConfig {
13
33
  configurationVersion?: string;
14
34
  policyVersion?: string;
15
35
  transport?: TransportAdapter;
36
+ initiator?: InitiatorConfig;
37
+ /**
38
+ * Bind a cancel-callback HTTP endpoint (RFC-0001 §7.2 Option A) when
39
+ * this participant's event loop starts. The server is closed
40
+ * automatically when {@link Participant.stop} is called. Parity with
41
+ * python-sdk's bootstrap `cancel_callback` field.
42
+ */
43
+ cancelCallback?: {
44
+ host: string;
45
+ port: number;
46
+ path: string;
47
+ };
16
48
  }
17
49
  export declare class Participant {
18
50
  readonly participantId: string;
@@ -25,14 +57,40 @@ export declare class Participant {
25
57
  private readonly dispatcher;
26
58
  private readonly session;
27
59
  private readonly transport;
60
+ private readonly initiatorConfig?;
61
+ private readonly participants;
62
+ private readonly modeVersion?;
63
+ private readonly configurationVersion?;
64
+ private readonly policyVersion?;
28
65
  private running;
29
66
  private lastPhase;
67
+ private cancelCallbackServer?;
68
+ private readonly cancelCallbackConfig?;
30
69
  constructor(config: ParticipantConfig);
31
70
  private createModeSession;
32
71
  private buildActions;
33
72
  on(messageType: string, handler: MessageHandler): Participant;
34
73
  onPhaseChange(phase: string, handler: PhaseChangeHandler): Participant;
35
74
  onTerminal(handler: TerminalHandler): Participant;
75
+ /** Whether {@link stop} has been called (or the loop has exited). */
76
+ get isStopped(): boolean;
36
77
  run(): Promise<void>;
78
+ /**
79
+ * Manually process a single envelope. Parity with python-sdk's
80
+ * {@code Participant.process_event}. Useful for deterministic unit tests
81
+ * and for driving the participant from a foreign event loop without
82
+ * installing a {@link TransportAdapter}.
83
+ */
84
+ processEvent(envelope: Envelope): Promise<void>;
85
+ private buildHandlerContext;
86
+ /** Returns true if a terminal state was reached. */
87
+ private processMessage;
37
88
  stop(): Promise<void>;
89
+ /**
90
+ * Attach a running cancel-callback HTTP server to this participant.
91
+ * The server is closed automatically when {@link stop} is called.
92
+ * Parity with python-sdk's `Participant.attach_cancel_callback_server`.
93
+ */
94
+ attachCancelCallbackServer(server: CancelCallbackServer): void;
95
+ private emitInitiatorEnvelopes;
38
96
  }