macp-sdk-typescript 0.4.0 → 0.5.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 +77 -0
- package/README.md +4 -3
- package/dist/agent/participant.d.ts +2 -0
- package/dist/agent/participant.js +1 -0
- package/dist/agent/runner.d.ts +1 -0
- package/dist/agent/runner.js +1 -0
- package/dist/agent/transports.d.ts +10 -0
- package/dist/agent/transports.js +13 -0
- package/dist/auth.d.ts +10 -5
- package/dist/auth.js +15 -15
- package/dist/base-session.d.ts +1 -0
- package/dist/base-session.js +3 -0
- package/dist/client.d.ts +60 -14
- package/dist/client.js +88 -30
- package/dist/decision.d.ts +1 -0
- package/dist/decision.js +2 -0
- package/dist/envelope.d.ts +20 -0
- package/dist/envelope.js +15 -0
- package/dist/errors.d.ts +10 -1
- package/dist/errors.js +11 -1
- package/dist/handoff.d.ts +1 -0
- package/dist/handoff.js +9 -1
- package/dist/policy.d.ts +35 -0
- package/dist/policy.js +18 -2
- package/dist/projections/handoff.d.ts +12 -0
- package/dist/projections/handoff.js +13 -0
- package/dist/proposal.d.ts +1 -0
- package/dist/proposal.js +2 -0
- package/dist/proto-registry.d.ts +10 -0
- package/dist/proto-registry.js +48 -2
- package/dist/quorum.d.ts +1 -0
- package/dist/quorum.js +2 -0
- package/dist/retry.d.ts +7 -0
- package/dist/task.d.ts +1 -0
- package/dist/task.js +2 -0
- package/dist/types.d.ts +18 -0
- package/dist/validation.d.ts +2 -0
- package/dist/validation.js +10 -0
- package/dist/watchers.d.ts +17 -13
- package/dist/watchers.js +26 -26
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,83 @@ 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.5.0] - 2026-07-06
|
|
8
|
+
|
|
9
|
+
Absorbs `macp-runtime` 0.5.0 and `@multiagentcoordinationprotocol/proto` 0.1.6
|
|
10
|
+
(resolves to ≥ 0.1.6; content identical through 0.1.8). Plan:
|
|
11
|
+
`plans/absorb-runtime-v0.5.0.md`.
|
|
12
|
+
|
|
13
|
+
**Requires `macp-runtime` ≥ 0.5.0** for: protobuf `Contribute` encoding, the
|
|
14
|
+
empty-`policy_version` commitment echo, the external task orchestrator, and the
|
|
15
|
+
bearer-only dev-auth flow (the runtime no longer reads `x-macp-agent-id`, and
|
|
16
|
+
refuses to start with no auth unless `MACP_ALLOW_INSECURE=1`). Pin `0.4.x` to
|
|
17
|
+
talk to an older runtime.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **`SessionStartPayload.maxSuspendMs`** (proto ≥ 0.1.5) — per-session cap on
|
|
22
|
+
cumulative suspended time before a `SUSPENDED` session `EXPIRE`s (RFC-MACP-0001
|
|
23
|
+
§7.5). Threaded through `buildSessionStartPayload`, every mode session's
|
|
24
|
+
`start()`, the `Participant` initiator config, and the bootstrap runner
|
|
25
|
+
(`session_start.max_suspend_ms`). `0`/absent = runtime default (7 days);
|
|
26
|
+
negatives are rejected client-side.
|
|
27
|
+
- **`HandoffAcceptPayload.implicit` decode support** (proto ≥ 0.1.6) — surfaced
|
|
28
|
+
read-only on `HandoffRecord.implicit` and `HandoffProjection.isImplicitlyAccepted()`
|
|
29
|
+
for the runtime-emitted synthetic accept (RFC-MACP-0010 §5.1). Client-submitted
|
|
30
|
+
`implicit` is stripped before encoding so it can never reach the wire.
|
|
31
|
+
- **`ListSessions` pagination** (proto ≥ 0.1.6) — new
|
|
32
|
+
`MacpClient.listSessionsPage({ pageSize, pageToken })` returning
|
|
33
|
+
`{ sessions, nextPageToken }`; `listSessions()` now transparently auto-paginates
|
|
34
|
+
so it still returns the complete listing.
|
|
35
|
+
- **`ext.multi_round.v1` `Contribute` uses canonical protobuf** — encodes as
|
|
36
|
+
`ContributePayload`; decode tries legacy JSON (`{"value":"..."}`) first for
|
|
37
|
+
byte-identical replay of pre-proto histories.
|
|
38
|
+
- **`MacpTransportError.code`** — carries the gRPC status name
|
|
39
|
+
(`RESOURCE_EXHAUSTED`, `FAILED_PRECONDITION`, `UNAUTHENTICATED`, …) surfaced on
|
|
40
|
+
unary calls, `MacpStream`, and watch streams, so consumers can distinguish
|
|
41
|
+
watch-stream lag (reconnect) from auth failure (don't) and passive-subscribe
|
|
42
|
+
resume below a compacted base.
|
|
43
|
+
- **`GrpcTransportAdapter.lastSequence`** — the 1-based accepted-envelope ordinal
|
|
44
|
+
of the last delivered envelope, a resume cursor for `sendSubscribe`.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- **Dev auth is bearer-only.** `Auth.devAgent(agentId)` now sends
|
|
49
|
+
`Authorization: Bearer <agentId>` (was the `x-macp-agent-id` header). The
|
|
50
|
+
runtime's dev fallback authenticates any bearer value as its sender, so
|
|
51
|
+
behavior is transparent for existing callers — but the wire header changed.
|
|
52
|
+
Integration/runbook: drop `MACP_ALLOW_DEV_SENDER_HEADER=1`, keep the now-mandatory
|
|
53
|
+
`MACP_ALLOW_INSECURE=1`.
|
|
54
|
+
- **`MacpClient.watchSignals` requires auth** (runtime 0.5.0) — routed through
|
|
55
|
+
`requireAuth`, so a missing credential fails fast client-side instead of as a
|
|
56
|
+
stream `UNAUTHENTICATED`. Breaking for anyone watching signals without auth.
|
|
57
|
+
- **`buildQuorumPolicy` validates percentage thresholds.** A `percentage`
|
|
58
|
+
`threshold.value` must be an integer 0–100 (the approval bar =
|
|
59
|
+
`ceil(value/100 × participants)`); a fractional value like `0.75` (previously a
|
|
60
|
+
silent ~1% bar) now throws `MacpSessionError`. Bug-surfacing by design.
|
|
61
|
+
- **`registerExtMode` pre-validates descriptors** — throws if
|
|
62
|
+
`terminalMessageTypes` lacks `'Commitment'` (mirrors the runtime, which rejects
|
|
63
|
+
such descriptors).
|
|
64
|
+
- **Canonical conformance fixtures + harness.** Vendored fixtures byte-synced to
|
|
65
|
+
the spec canonical pack (fully-qualified `payload_type`, `expected_error_code`,
|
|
66
|
+
`schema.json`); the harness parses FQ names only, with a format guard rejecting
|
|
67
|
+
legacy shorthand.
|
|
68
|
+
- **`SessionStartPayload` bodies now emit `maxSuspendMs`** (`0` when unset).
|
|
69
|
+
|
|
70
|
+
### Removed
|
|
71
|
+
|
|
72
|
+
- **`AuthConfig.agentId`** and the `x-macp-agent-id` metadata path — no supported
|
|
73
|
+
runtime reads the header. Use `Auth.devAgent` / `Auth.bearer`.
|
|
74
|
+
- **`SessionLifecycleWatcher.events()` / `nextEvent()`** — deprecated aliases;
|
|
75
|
+
use `changes()` / `nextChange()`.
|
|
76
|
+
- **`MacpClient._watchModeRegistry` / `_watchRoots` / `_watchSignals` /
|
|
77
|
+
`_watchPolicies`** — deprecated underscored aliases; use the un-prefixed
|
|
78
|
+
`watch*` methods.
|
|
79
|
+
|
|
80
|
+
### Fixed
|
|
81
|
+
|
|
82
|
+
- `MacpClient.clientVersion` default was a stale `'0.3.0'`; now `'0.5.0'`.
|
|
83
|
+
|
|
7
84
|
## [0.4.0] - 2026-06-22
|
|
8
85
|
|
|
9
86
|
Adopts `@multiagentcoordinationprotocol/proto` 0.1.3 — session
|
package/README.md
CHANGED
|
@@ -297,7 +297,8 @@ See [`docs/api/cancel-callback.md`](docs/api/cancel-callback.md) and
|
|
|
297
297
|
## Authentication
|
|
298
298
|
|
|
299
299
|
```typescript
|
|
300
|
-
// Development (
|
|
300
|
+
// Development (bearer-only; sends Authorization: Bearer my-agent).
|
|
301
|
+
// Requires the runtime to run with MACP_ALLOW_INSECURE=1.
|
|
301
302
|
const auth = Auth.devAgent('my-agent');
|
|
302
303
|
|
|
303
304
|
// Production (Bearer token with authenticated identity — RFC-MACP-0004 §4).
|
|
@@ -414,10 +415,10 @@ Run the full SDK against a live MACP runtime:
|
|
|
414
415
|
|
|
415
416
|
```bash
|
|
416
417
|
# Build and start the runtime
|
|
417
|
-
docker build -t macp-runtime ../runtime/
|
|
418
|
+
docker build -t macp-runtime ../macp-runtime/
|
|
418
419
|
docker run -d --name macp-runtime-test -p 50051:50051 \
|
|
419
420
|
-e MACP_BIND_ADDR=0.0.0.0:50051 -e MACP_ALLOW_INSECURE=1 \
|
|
420
|
-
-e
|
|
421
|
+
-e MACP_MEMORY_ONLY=1 macp-runtime
|
|
421
422
|
|
|
422
423
|
# Run tests
|
|
423
424
|
npm run test:integration
|
|
@@ -9,6 +9,8 @@ export interface InitiatorConfig {
|
|
|
9
9
|
intent: string;
|
|
10
10
|
participants: string[];
|
|
11
11
|
ttlMs: number;
|
|
12
|
+
/** Per-session max-suspend cap (ms, proto ≥ 0.1.5). 0/absent = runtime default. */
|
|
13
|
+
maxSuspendMs?: number;
|
|
12
14
|
contextId?: string;
|
|
13
15
|
extensions?: Record<string, Buffer>;
|
|
14
16
|
context?: Record<string, unknown>;
|
package/dist/agent/runner.d.ts
CHANGED
package/dist/agent/runner.js
CHANGED
|
@@ -11,7 +11,17 @@ export declare class GrpcTransportAdapter implements TransportAdapter {
|
|
|
11
11
|
private readonly auth?;
|
|
12
12
|
private stream;
|
|
13
13
|
private seq;
|
|
14
|
+
private delivered;
|
|
14
15
|
constructor(client: MacpClient, sessionId: string, auth?: AuthConfig | undefined);
|
|
16
|
+
/**
|
|
17
|
+
* The server passive-subscribe ordinal of the last delivered envelope (the
|
|
18
|
+
* 1-based count of accepted envelopes delivered on this stream, RFC-MACP-0006
|
|
19
|
+
* §3.2). `0` before anything is delivered. Pass this as `afterSequence` to
|
|
20
|
+
* `MacpStream.sendSubscribe` on a reconnect to resume exactly-once — ordinals
|
|
21
|
+
* are stable across compaction/restart. Distinct from `IncomingMessage.seq`,
|
|
22
|
+
* which is a client-local 0-based delivery index.
|
|
23
|
+
*/
|
|
24
|
+
get lastSequence(): number;
|
|
15
25
|
start(): AsyncIterable<IncomingMessage>;
|
|
16
26
|
stop(): Promise<void>;
|
|
17
27
|
}
|
package/dist/agent/transports.js
CHANGED
|
@@ -18,11 +18,23 @@ class GrpcTransportAdapter {
|
|
|
18
18
|
auth;
|
|
19
19
|
stream = null;
|
|
20
20
|
seq = 0;
|
|
21
|
+
delivered = 0;
|
|
21
22
|
constructor(client, sessionId, auth) {
|
|
22
23
|
this.client = client;
|
|
23
24
|
this.sessionId = sessionId;
|
|
24
25
|
this.auth = auth;
|
|
25
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* The server passive-subscribe ordinal of the last delivered envelope (the
|
|
29
|
+
* 1-based count of accepted envelopes delivered on this stream, RFC-MACP-0006
|
|
30
|
+
* §3.2). `0` before anything is delivered. Pass this as `afterSequence` to
|
|
31
|
+
* `MacpStream.sendSubscribe` on a reconnect to resume exactly-once — ordinals
|
|
32
|
+
* are stable across compaction/restart. Distinct from `IncomingMessage.seq`,
|
|
33
|
+
* which is a client-local 0-based delivery index.
|
|
34
|
+
*/
|
|
35
|
+
get lastSequence() {
|
|
36
|
+
return this.delivered;
|
|
37
|
+
}
|
|
26
38
|
async *start() {
|
|
27
39
|
this.stream = this.client.openStream({ auth: this.auth });
|
|
28
40
|
// RFC-MACP-0006-A1: Subscribe to the session with history replay.
|
|
@@ -33,6 +45,7 @@ class GrpcTransportAdapter {
|
|
|
33
45
|
for await (const envelope of this.stream.responses()) {
|
|
34
46
|
if (envelope.sessionId !== this.sessionId)
|
|
35
47
|
continue;
|
|
48
|
+
this.delivered++;
|
|
36
49
|
yield normalizeEnvelope(envelope, (mode, mt, p) => this.client.protoRegistry.decodeKnownPayload(mode, mt, p), this.seq++);
|
|
37
50
|
}
|
|
38
51
|
}
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as grpc from '@grpc/grpc-js';
|
|
2
2
|
export interface AuthConfig {
|
|
3
3
|
bearerToken?: string;
|
|
4
|
-
agentId?: string;
|
|
5
4
|
senderHint?: string;
|
|
6
5
|
/**
|
|
7
6
|
* The authenticated sender this credential represents. When present, the SDK
|
|
@@ -22,10 +21,16 @@ export type BearerAuthOptions = string | {
|
|
|
22
21
|
};
|
|
23
22
|
export declare const Auth: {
|
|
24
23
|
/**
|
|
25
|
-
* Dev-mode agent identity
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* Dev-mode agent identity (bearer-only, runtime ≥ 0.5.0). Sends
|
|
25
|
+
* `Authorization: Bearer <agentId>`; the runtime's dev fallback authenticates
|
|
26
|
+
* any bearer value as the sender of that value, so `Auth.devAgent('alice')`
|
|
27
|
+
* authenticates as sender `alice`. Requires the runtime to be started with
|
|
28
|
+
* `MACP_ALLOW_INSECURE=1` (it refuses to start with no auth configured
|
|
29
|
+
* otherwise). Not for production — use {@link Auth.bearer}.
|
|
30
|
+
*
|
|
31
|
+
* The legacy `x-macp-agent-id` header was removed in 0.5.0: no supported
|
|
32
|
+
* runtime reads it. Does not set {@link AuthConfig.expectedSender}; dev flows
|
|
33
|
+
* stay permissive so tests can reuse a single credential across senders.
|
|
29
34
|
*/
|
|
30
35
|
devAgent(agentId: string): AuthConfig;
|
|
31
36
|
/**
|
package/dist/auth.js
CHANGED
|
@@ -42,13 +42,19 @@ const grpc = __importStar(require("@grpc/grpc-js"));
|
|
|
42
42
|
const errors_1 = require("./errors");
|
|
43
43
|
exports.Auth = {
|
|
44
44
|
/**
|
|
45
|
-
* Dev-mode agent identity
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
45
|
+
* Dev-mode agent identity (bearer-only, runtime ≥ 0.5.0). Sends
|
|
46
|
+
* `Authorization: Bearer <agentId>`; the runtime's dev fallback authenticates
|
|
47
|
+
* any bearer value as the sender of that value, so `Auth.devAgent('alice')`
|
|
48
|
+
* authenticates as sender `alice`. Requires the runtime to be started with
|
|
49
|
+
* `MACP_ALLOW_INSECURE=1` (it refuses to start with no auth configured
|
|
50
|
+
* otherwise). Not for production — use {@link Auth.bearer}.
|
|
51
|
+
*
|
|
52
|
+
* The legacy `x-macp-agent-id` header was removed in 0.5.0: no supported
|
|
53
|
+
* runtime reads it. Does not set {@link AuthConfig.expectedSender}; dev flows
|
|
54
|
+
* stay permissive so tests can reuse a single credential across senders.
|
|
49
55
|
*/
|
|
50
56
|
devAgent(agentId) {
|
|
51
|
-
return { agentId, senderHint: agentId };
|
|
57
|
+
return { bearerToken: agentId, senderHint: agentId };
|
|
52
58
|
},
|
|
53
59
|
/**
|
|
54
60
|
* Production bearer-token credential. Pass `{ expectedSender }` to have the
|
|
@@ -75,17 +81,14 @@ exports.Auth = {
|
|
|
75
81
|
},
|
|
76
82
|
};
|
|
77
83
|
function validateAuth(auth) {
|
|
78
|
-
if (!auth.bearerToken
|
|
79
|
-
throw new Error('
|
|
80
|
-
}
|
|
81
|
-
if (auth.bearerToken && auth.agentId) {
|
|
82
|
-
throw new Error('choose either bearerToken or agentId, not both');
|
|
84
|
+
if (!auth.bearerToken) {
|
|
85
|
+
throw new Error('bearerToken is required');
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
function authSender(auth) {
|
|
86
89
|
if (!auth)
|
|
87
90
|
return undefined;
|
|
88
|
-
return auth.expectedSender ?? auth.senderHint
|
|
91
|
+
return auth.expectedSender ?? auth.senderHint;
|
|
89
92
|
}
|
|
90
93
|
/**
|
|
91
94
|
* Throw {@link MacpIdentityMismatchError} when a caller-supplied `sender`
|
|
@@ -104,9 +107,6 @@ function assertSenderMatchesIdentity(auth, sender) {
|
|
|
104
107
|
function metadataFromAuth(auth) {
|
|
105
108
|
validateAuth(auth);
|
|
106
109
|
const metadata = new grpc.Metadata();
|
|
107
|
-
|
|
108
|
-
metadata.set('authorization', `Bearer ${auth.bearerToken}`);
|
|
109
|
-
if (auth.agentId)
|
|
110
|
-
metadata.set('x-macp-agent-id', auth.agentId);
|
|
110
|
+
metadata.set('authorization', `Bearer ${auth.bearerToken}`);
|
|
111
111
|
return metadata;
|
|
112
112
|
}
|
package/dist/base-session.d.ts
CHANGED
package/dist/base-session.js
CHANGED
|
@@ -58,10 +58,13 @@ class BaseSession {
|
|
|
58
58
|
/** Send SessionStart and begin tracking via the projection. */
|
|
59
59
|
async start(input) {
|
|
60
60
|
(0, validation_1.validateParticipantCount)(input.participants.length);
|
|
61
|
+
if (input.maxSuspendMs !== undefined)
|
|
62
|
+
(0, validation_1.validateMaxSuspendMs)(input.maxSuspendMs);
|
|
61
63
|
const payload = (0, envelope_1.buildSessionStartPayload)({
|
|
62
64
|
intent: input.intent,
|
|
63
65
|
participants: input.participants,
|
|
64
66
|
ttlMs: input.ttlMs,
|
|
67
|
+
maxSuspendMs: input.maxSuspendMs,
|
|
65
68
|
contextId: input.contextId,
|
|
66
69
|
extensions: input.extensions,
|
|
67
70
|
roots: input.roots,
|
package/dist/client.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ interface MacpClientOptions {
|
|
|
23
23
|
clientVersion?: string;
|
|
24
24
|
protoDir?: string;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Map a gRPC `ServiceError.code` (numeric `grpc.status`) to its status name
|
|
28
|
+
* (e.g. `8` → `'RESOURCE_EXHAUSTED'`). Returns `undefined` for non-numeric or
|
|
29
|
+
* unknown codes. Used to populate {@link MacpTransportError.code}.
|
|
30
|
+
*/
|
|
31
|
+
export declare function grpcStatusName(code: unknown): string | undefined;
|
|
26
32
|
export type InlineErrorCallback = (error: {
|
|
27
33
|
code?: string;
|
|
28
34
|
message?: string;
|
|
@@ -36,9 +42,19 @@ export declare class MacpStream {
|
|
|
36
42
|
onInlineError(callback: InlineErrorCallback): void;
|
|
37
43
|
send(envelope: Envelope): Promise<void>;
|
|
38
44
|
/**
|
|
39
|
-
* RFC-MACP-0006
|
|
40
|
-
* + live broadcast. The runtime replays accepted envelopes
|
|
41
|
-
* `afterSequence
|
|
45
|
+
* RFC-MACP-0006 §3.2: Send a subscribe-only frame to receive session history
|
|
46
|
+
* + live broadcast. The runtime replays accepted envelopes strictly after
|
|
47
|
+
* `afterSequence`, then continues with live broadcast.
|
|
48
|
+
*
|
|
49
|
+
* `afterSequence` is the **1-based accepted-envelope ordinal**, exclusive:
|
|
50
|
+
* `0` (default) replays from the very start; `k` replays envelopes with
|
|
51
|
+
* ordinal `> k`. Clients derive the ordinal by counting delivered envelopes
|
|
52
|
+
* (the Nth accepted envelope has ordinal N) — see
|
|
53
|
+
* `IncomingMessage.seq`, which is exactly this ordinal under the new contract.
|
|
54
|
+
* Ordinals are stable across log compaction and runtime restart. Resuming
|
|
55
|
+
* below a compacted base returns `FAILED_PRECONDITION` (inspectable via
|
|
56
|
+
* `MacpTransportError.code`) rather than silently skipping history (runtime
|
|
57
|
+
* ≥ 0.5.0; older runtimes compared inclusively against a raw log index).
|
|
42
58
|
*/
|
|
43
59
|
sendSubscribe(sessionId: string, afterSequence?: number): Promise<void>;
|
|
44
60
|
responses(): AsyncGenerator<Envelope, void, void>;
|
|
@@ -135,6 +151,20 @@ export declare class MacpClient {
|
|
|
135
151
|
listRoots(deadlineMs?: number): Promise<{
|
|
136
152
|
roots: Root[];
|
|
137
153
|
}>;
|
|
154
|
+
/**
|
|
155
|
+
* Register an extension-mode descriptor (runtime 0.5.0 guardrails,
|
|
156
|
+
* change-review A5):
|
|
157
|
+
* - the descriptor MUST declare `Commitment` among `terminalMessageTypes` —
|
|
158
|
+
* an ext mode without a terminal `Commitment` can never resolve, so the
|
|
159
|
+
* runtime rejects it. This method fails fast client-side to match.
|
|
160
|
+
* - a later {@link promoteMode} into the reserved `macp.mode.*` namespace is
|
|
161
|
+
* rejected by the runtime.
|
|
162
|
+
* - a SessionStart with an empty `mode_version` binds the registered
|
|
163
|
+
* descriptor's `modeVersion`; a subsequent Commitment must echo that bound
|
|
164
|
+
* version (echoing `""` no longer matches vacuously). `BaseSession`
|
|
165
|
+
* defaults `modeVersion` to `'1.0.0'`, so set the descriptor's version to
|
|
166
|
+
* match, or override the session's `modeVersion`.
|
|
167
|
+
*/
|
|
138
168
|
registerExtMode(descriptor: ModeDescriptor, options?: {
|
|
139
169
|
auth?: AuthConfig;
|
|
140
170
|
deadlineMs?: number;
|
|
@@ -179,30 +209,46 @@ export declare class MacpClient {
|
|
|
179
209
|
auth?: AuthConfig;
|
|
180
210
|
deadlineMs?: number;
|
|
181
211
|
}): Promise<PolicyDescriptor[]>;
|
|
212
|
+
/**
|
|
213
|
+
* Fetch a single page of sessions (proto ≥ 0.1.6). `pageSize: 0` (or absent)
|
|
214
|
+
* lets the server choose the page size; the server MAY cap it. Callers MUST
|
|
215
|
+
* NOT assume the listing is complete unless `nextPageToken` is empty. Pass a
|
|
216
|
+
* returned non-empty `nextPageToken` back as `pageToken` to fetch the next
|
|
217
|
+
* page; a stale token yields `INVALID_ARGUMENT`.
|
|
218
|
+
*/
|
|
219
|
+
listSessionsPage(options?: {
|
|
220
|
+
pageSize?: number;
|
|
221
|
+
pageToken?: string;
|
|
222
|
+
auth?: AuthConfig;
|
|
223
|
+
deadlineMs?: number;
|
|
224
|
+
}): Promise<{
|
|
225
|
+
sessions: SessionMetadata[];
|
|
226
|
+
nextPageToken: string;
|
|
227
|
+
}>;
|
|
228
|
+
/**
|
|
229
|
+
* Enumerate ALL sessions, transparently walking pages until the runtime
|
|
230
|
+
* returns an empty `nextPageToken`. Preserves the "complete list" semantics
|
|
231
|
+
* this method has always documented, even against runtimes that cap page
|
|
232
|
+
* sizes (proto ≥ 0.1.6). For manual page control, use {@link listSessionsPage}.
|
|
233
|
+
*/
|
|
182
234
|
listSessions(options?: {
|
|
183
235
|
auth?: AuthConfig;
|
|
184
236
|
deadlineMs?: number;
|
|
237
|
+
pageSize?: number;
|
|
185
238
|
}): Promise<SessionMetadata[]>;
|
|
186
239
|
watchSessions(auth?: AuthConfig): grpc.ClientReadableStream<any>;
|
|
187
240
|
watchPolicies(auth?: AuthConfig): grpc.ClientReadableStream<any>;
|
|
188
|
-
/** @deprecated Use {@link watchPolicies}. Scheduled for removal in 0.4.0. */
|
|
189
|
-
_watchPolicies(auth?: AuthConfig): grpc.ClientReadableStream<any>;
|
|
190
241
|
openStream(options?: {
|
|
191
242
|
auth?: AuthConfig;
|
|
192
243
|
}): MacpStream;
|
|
193
244
|
watchModeRegistry(auth?: AuthConfig): grpc.ClientReadableStream<any>;
|
|
194
245
|
watchRoots(auth?: AuthConfig): grpc.ClientReadableStream<any>;
|
|
195
|
-
watchSignals(auth?: AuthConfig): grpc.ClientReadableStream<any>;
|
|
196
246
|
/**
|
|
197
|
-
*
|
|
198
|
-
* {@link
|
|
199
|
-
*
|
|
247
|
+
* Subscribe to the ambient signal plane. Requires auth as of runtime 0.5.0 —
|
|
248
|
+
* routed through {@link requireAuth} so a missing credential fails fast with a
|
|
249
|
+
* clear client-side error instead of a stream `UNAUTHENTICATED`.
|
|
200
250
|
*/
|
|
201
|
-
|
|
202
|
-
/** @deprecated Use {@link watchRoots}. Scheduled for removal in 0.4.0. */
|
|
203
|
-
_watchRoots(auth?: AuthConfig): grpc.ClientReadableStream<any>;
|
|
204
|
-
/** @deprecated Use {@link watchSignals}. Scheduled for removal in 0.4.0. */
|
|
205
|
-
_watchSignals(auth?: AuthConfig): grpc.ClientReadableStream<any>;
|
|
251
|
+
watchSignals(auth?: AuthConfig): grpc.ClientReadableStream<any>;
|
|
206
252
|
sendSignal(options: {
|
|
207
253
|
signalType: string;
|
|
208
254
|
data?: Buffer;
|
package/dist/client.js
CHANGED
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.MacpClient = exports.MacpStream = void 0;
|
|
37
|
+
exports.grpcStatusName = grpcStatusName;
|
|
37
38
|
/* eslint-disable @typescript-eslint/no-explicit-any --
|
|
38
39
|
* The gRPC service client returned by `protoLoader.loadSync()` is typed as
|
|
39
40
|
* `any` by `@grpc/proto-loader`; method signatures (Send, StreamSession,
|
|
@@ -98,6 +99,17 @@ class AsyncQueue {
|
|
|
98
99
|
});
|
|
99
100
|
}
|
|
100
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Map a gRPC `ServiceError.code` (numeric `grpc.status`) to its status name
|
|
104
|
+
* (e.g. `8` → `'RESOURCE_EXHAUSTED'`). Returns `undefined` for non-numeric or
|
|
105
|
+
* unknown codes. Used to populate {@link MacpTransportError.code}.
|
|
106
|
+
*/
|
|
107
|
+
function grpcStatusName(code) {
|
|
108
|
+
if (typeof code !== 'number')
|
|
109
|
+
return undefined;
|
|
110
|
+
const name = grpc.status[code];
|
|
111
|
+
return typeof name === 'string' ? name : undefined;
|
|
112
|
+
}
|
|
101
113
|
const TIMEOUT = Symbol('stream-read-timeout');
|
|
102
114
|
const STREAM_END = Symbol('stream-end');
|
|
103
115
|
class MacpStream {
|
|
@@ -120,7 +132,7 @@ class MacpStream {
|
|
|
120
132
|
}
|
|
121
133
|
});
|
|
122
134
|
call.on('error', (error) => {
|
|
123
|
-
this.queue.push(new errors_1.MacpTransportError(error.details || error.message));
|
|
135
|
+
this.queue.push(new errors_1.MacpTransportError(error.details || error.message, grpcStatusName(error.code)));
|
|
124
136
|
});
|
|
125
137
|
call.on('end', () => {
|
|
126
138
|
this.queue.push(STREAM_END);
|
|
@@ -142,9 +154,19 @@ class MacpStream {
|
|
|
142
154
|
});
|
|
143
155
|
}
|
|
144
156
|
/**
|
|
145
|
-
* RFC-MACP-0006
|
|
146
|
-
* + live broadcast. The runtime replays accepted envelopes
|
|
147
|
-
* `afterSequence
|
|
157
|
+
* RFC-MACP-0006 §3.2: Send a subscribe-only frame to receive session history
|
|
158
|
+
* + live broadcast. The runtime replays accepted envelopes strictly after
|
|
159
|
+
* `afterSequence`, then continues with live broadcast.
|
|
160
|
+
*
|
|
161
|
+
* `afterSequence` is the **1-based accepted-envelope ordinal**, exclusive:
|
|
162
|
+
* `0` (default) replays from the very start; `k` replays envelopes with
|
|
163
|
+
* ordinal `> k`. Clients derive the ordinal by counting delivered envelopes
|
|
164
|
+
* (the Nth accepted envelope has ordinal N) — see
|
|
165
|
+
* `IncomingMessage.seq`, which is exactly this ordinal under the new contract.
|
|
166
|
+
* Ordinals are stable across log compaction and runtime restart. Resuming
|
|
167
|
+
* below a compacted base returns `FAILED_PRECONDITION` (inspectable via
|
|
168
|
+
* `MacpTransportError.code`) rather than silently skipping history (runtime
|
|
169
|
+
* ≥ 0.5.0; older runtimes compared inclusively against a raw log index).
|
|
148
170
|
*/
|
|
149
171
|
sendSubscribe(sessionId, afterSequence = 0) {
|
|
150
172
|
if (this.closed)
|
|
@@ -223,7 +245,7 @@ class MacpClient {
|
|
|
223
245
|
}
|
|
224
246
|
this.defaultDeadlineMs = options.defaultDeadlineMs;
|
|
225
247
|
this.clientName = options.clientName ?? 'macp-sdk-typescript';
|
|
226
|
-
this.clientVersion = options.clientVersion ?? '0.
|
|
248
|
+
this.clientVersion = options.clientVersion ?? '0.5.0';
|
|
227
249
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
228
250
|
const { protoDir: defaultProtoDir } = require('@multiagentcoordinationprotocol/proto');
|
|
229
251
|
const protoDir = options.protoDir ?? defaultProtoDir;
|
|
@@ -266,7 +288,7 @@ class MacpClient {
|
|
|
266
288
|
return new Promise((resolve, reject) => {
|
|
267
289
|
const callback = (error, response) => {
|
|
268
290
|
if (error)
|
|
269
|
-
reject(new errors_1.MacpTransportError(error.details || error.message));
|
|
291
|
+
reject(new errors_1.MacpTransportError(error.details || error.message, grpcStatusName(error.code)));
|
|
270
292
|
else
|
|
271
293
|
resolve(response);
|
|
272
294
|
};
|
|
@@ -382,7 +404,25 @@ class MacpClient {
|
|
|
382
404
|
async listRoots(deadlineMs) {
|
|
383
405
|
return this.unary('ListRoots', {}, undefined, deadlineMs);
|
|
384
406
|
}
|
|
407
|
+
/**
|
|
408
|
+
* Register an extension-mode descriptor (runtime 0.5.0 guardrails,
|
|
409
|
+
* change-review A5):
|
|
410
|
+
* - the descriptor MUST declare `Commitment` among `terminalMessageTypes` —
|
|
411
|
+
* an ext mode without a terminal `Commitment` can never resolve, so the
|
|
412
|
+
* runtime rejects it. This method fails fast client-side to match.
|
|
413
|
+
* - a later {@link promoteMode} into the reserved `macp.mode.*` namespace is
|
|
414
|
+
* rejected by the runtime.
|
|
415
|
+
* - a SessionStart with an empty `mode_version` binds the registered
|
|
416
|
+
* descriptor's `modeVersion`; a subsequent Commitment must echo that bound
|
|
417
|
+
* version (echoing `""` no longer matches vacuously). `BaseSession`
|
|
418
|
+
* defaults `modeVersion` to `'1.0.0'`, so set the descriptor's version to
|
|
419
|
+
* match, or override the session's `modeVersion`.
|
|
420
|
+
*/
|
|
385
421
|
async registerExtMode(descriptor, options) {
|
|
422
|
+
if (!descriptor.terminalMessageTypes?.includes('Commitment')) {
|
|
423
|
+
throw new errors_1.MacpSessionError(`ext-mode descriptor '${descriptor.mode}' must declare 'Commitment' in terminalMessageTypes; ` +
|
|
424
|
+
'a mode without a terminal Commitment can never resolve and the runtime rejects it.');
|
|
425
|
+
}
|
|
386
426
|
const auth = this.requireAuth(options?.auth);
|
|
387
427
|
return this.unary('RegisterExtMode', { modeDescriptor: descriptor }, auth, options?.deadlineMs);
|
|
388
428
|
}
|
|
@@ -412,10 +452,42 @@ class MacpClient {
|
|
|
412
452
|
const res = await this.unary('ListPolicies', { mode: mode || '' }, auth, options?.deadlineMs);
|
|
413
453
|
return res.descriptors || [];
|
|
414
454
|
}
|
|
415
|
-
|
|
455
|
+
/**
|
|
456
|
+
* Fetch a single page of sessions (proto ≥ 0.1.6). `pageSize: 0` (or absent)
|
|
457
|
+
* lets the server choose the page size; the server MAY cap it. Callers MUST
|
|
458
|
+
* NOT assume the listing is complete unless `nextPageToken` is empty. Pass a
|
|
459
|
+
* returned non-empty `nextPageToken` back as `pageToken` to fetch the next
|
|
460
|
+
* page; a stale token yields `INVALID_ARGUMENT`.
|
|
461
|
+
*/
|
|
462
|
+
async listSessionsPage(options) {
|
|
416
463
|
const auth = this.requireAuth(options?.auth);
|
|
417
|
-
const res = await this.unary('ListSessions', {}, auth, options?.deadlineMs);
|
|
418
|
-
return res.sessions
|
|
464
|
+
const res = await this.unary('ListSessions', { pageSize: options?.pageSize ?? 0, pageToken: options?.pageToken ?? '' }, auth, options?.deadlineMs);
|
|
465
|
+
return { sessions: res.sessions ?? [], nextPageToken: res.nextPageToken ?? '' };
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Enumerate ALL sessions, transparently walking pages until the runtime
|
|
469
|
+
* returns an empty `nextPageToken`. Preserves the "complete list" semantics
|
|
470
|
+
* this method has always documented, even against runtimes that cap page
|
|
471
|
+
* sizes (proto ≥ 0.1.6). For manual page control, use {@link listSessionsPage}.
|
|
472
|
+
*/
|
|
473
|
+
async listSessions(options) {
|
|
474
|
+
const all = [];
|
|
475
|
+
let pageToken = '';
|
|
476
|
+
// Bound the walk defensively so a misbehaving runtime that never returns an
|
|
477
|
+
// empty token cannot spin forever.
|
|
478
|
+
for (let page = 0; page < 100_000; page++) {
|
|
479
|
+
const res = await this.listSessionsPage({
|
|
480
|
+
pageSize: options?.pageSize,
|
|
481
|
+
pageToken,
|
|
482
|
+
auth: options?.auth,
|
|
483
|
+
deadlineMs: options?.deadlineMs,
|
|
484
|
+
});
|
|
485
|
+
all.push(...res.sessions);
|
|
486
|
+
if (!res.nextPageToken)
|
|
487
|
+
return all;
|
|
488
|
+
pageToken = res.nextPageToken;
|
|
489
|
+
}
|
|
490
|
+
return all;
|
|
419
491
|
}
|
|
420
492
|
watchSessions(auth) {
|
|
421
493
|
const metadata = this.metadata(auth);
|
|
@@ -425,10 +497,6 @@ class MacpClient {
|
|
|
425
497
|
const metadata = this.metadata(auth);
|
|
426
498
|
return metadata ? this.client.WatchPolicies({}, metadata) : this.client.WatchPolicies({});
|
|
427
499
|
}
|
|
428
|
-
/** @deprecated Use {@link watchPolicies}. Scheduled for removal in 0.4.0. */
|
|
429
|
-
_watchPolicies(auth) {
|
|
430
|
-
return this.watchPolicies(auth);
|
|
431
|
-
}
|
|
432
500
|
openStream(options) {
|
|
433
501
|
const auth = this.requireAuth(options?.auth);
|
|
434
502
|
const metadata = this.metadata(auth);
|
|
@@ -443,25 +511,15 @@ class MacpClient {
|
|
|
443
511
|
const metadata = this.metadata(auth);
|
|
444
512
|
return metadata ? this.client.WatchRoots({}, metadata) : this.client.WatchRoots({});
|
|
445
513
|
}
|
|
446
|
-
watchSignals(auth) {
|
|
447
|
-
const metadata = this.metadata(auth);
|
|
448
|
-
return metadata ? this.client.WatchSignals({}, metadata) : this.client.WatchSignals({});
|
|
449
|
-
}
|
|
450
514
|
/**
|
|
451
|
-
*
|
|
452
|
-
* {@link
|
|
453
|
-
*
|
|
515
|
+
* Subscribe to the ambient signal plane. Requires auth as of runtime 0.5.0 —
|
|
516
|
+
* routed through {@link requireAuth} so a missing credential fails fast with a
|
|
517
|
+
* clear client-side error instead of a stream `UNAUTHENTICATED`.
|
|
454
518
|
*/
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
_watchRoots(auth) {
|
|
460
|
-
return this.watchRoots(auth);
|
|
461
|
-
}
|
|
462
|
-
/** @deprecated Use {@link watchSignals}. Scheduled for removal in 0.4.0. */
|
|
463
|
-
_watchSignals(auth) {
|
|
464
|
-
return this.watchSignals(auth);
|
|
519
|
+
watchSignals(auth) {
|
|
520
|
+
const selected = this.requireAuth(auth);
|
|
521
|
+
const metadata = (0, auth_1.metadataFromAuth)(selected);
|
|
522
|
+
return this.client.WatchSignals({}, metadata);
|
|
465
523
|
}
|
|
466
524
|
async sendSignal(options) {
|
|
467
525
|
(0, validation_1.validateSignalType)(options.signalType, options.data);
|
package/dist/decision.d.ts
CHANGED
package/dist/decision.js
CHANGED
|
@@ -40,6 +40,7 @@ class DecisionSession {
|
|
|
40
40
|
intent: input.intent,
|
|
41
41
|
participants: input.participants,
|
|
42
42
|
ttlMs: input.ttlMs,
|
|
43
|
+
maxSuspendMs: input.maxSuspendMs,
|
|
43
44
|
modeVersion: this.modeVersion,
|
|
44
45
|
configurationVersion: this.configurationVersion,
|
|
45
46
|
});
|
|
@@ -47,6 +48,7 @@ class DecisionSession {
|
|
|
47
48
|
intent: input.intent,
|
|
48
49
|
participants: input.participants,
|
|
49
50
|
ttlMs: input.ttlMs,
|
|
51
|
+
maxSuspendMs: input.maxSuspendMs,
|
|
50
52
|
contextId: input.contextId,
|
|
51
53
|
extensions: input.extensions,
|
|
52
54
|
roots: input.roots,
|