@canonmsg/agent-sdk 12.6.1 → 13.0.2

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 (30) hide show
  1. package/README.md +23 -21
  2. package/dist/chunks/{chunk-S7BV74DN.js → chunk-5WPAB5MB.js} +293 -8
  3. package/dist/chunks/{chunk-DAJ7L7TN.js → chunk-DNHJGAEL.js} +378 -663
  4. package/dist/chunks/{chunk-HH7KR22P.js → chunk-DTAWEQCM.js} +2 -2
  5. package/dist/chunks/{chunk-5J4YPLNW.js → chunk-TYZT346O.js} +266 -1217
  6. package/dist/chunks/{chunk-QK37HAHC.js → chunk-YHDDOADK.js} +1 -1
  7. package/dist/chunks/{chunk-FVYKLH6I.js → chunk-YJUPKU47.js} +20 -5
  8. package/dist/chunks/{mls-crypto-4DZT2UFH.js → mls-crypto-NZVMSUFU.js} +2 -2
  9. package/dist/cli.js +32 -36
  10. package/dist/drivers/subprocess.d.ts +4 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +6 -6
  13. package/dist/internal/backend-contracts/mlsDevGroup.d.ts +17 -0
  14. package/dist/internal/core/completed-output-journal.d.ts +0 -5
  15. package/dist/internal/core/index.d.ts +3 -9
  16. package/dist/internal/core/retry.d.ts +2 -89
  17. package/dist/internal/core/silent-turn.d.ts +4 -33
  18. package/dist/internal/endpoint/engine.d.ts +3 -0
  19. package/dist/internal/endpoint/mls-dev-groups.d.ts +12 -0
  20. package/dist/internal/endpoint/mls-dev-text.d.ts +29 -0
  21. package/dist/internal/endpoint/transport.d.ts +1 -1
  22. package/dist/media.js +4 -4
  23. package/dist/mls-wasm-host.js +3 -3
  24. package/dist/runner/mls.d.ts +4 -7
  25. package/dist/runner/runner.d.ts +9 -12
  26. package/dist/runner/types.d.ts +31 -0
  27. package/package.json +1 -1
  28. package/dist/internal/core/approval-manager.d.ts +0 -43
  29. package/dist/internal/core/runtime-request-manager.d.ts +0 -283
  30. package/dist/internal/core/turn-verbosity.d.ts +0 -79
@@ -9,7 +9,7 @@ import {
9
9
  parseMlsDevEnrollmentPrincipal,
10
10
  parseMlsDevIssuerKeyVersion,
11
11
  parseMlsDevReceiptKeyVersion
12
- } from "./chunk-S7BV74DN.js";
12
+ } from "./chunk-5WPAB5MB.js";
13
13
 
14
14
  // ../endpoint/src/mls-crypto.ts
15
15
  import { ed25519 } from "@noble/curves/ed25519.js";
@@ -43,7 +43,7 @@ import {
43
43
  parseMlsDevKeyPackagePreparation,
44
44
  parseMlsDevKeyPackagePublicationReceipt,
45
45
  parseMlsDevKeyPackagePublish
46
- } from "./chunk-S7BV74DN.js";
46
+ } from "./chunk-5WPAB5MB.js";
47
47
 
48
48
  // ../endpoint/src/events.ts
49
49
  function createEndpointEventHub(input) {
@@ -611,13 +611,21 @@ __name(validateEndpointContentBoundary, "validateEndpointContentBoundary");
611
611
  function createHttpEndpointTransport(options) {
612
612
  const fetcher = options.fetch ?? globalThis.fetch;
613
613
  const clientHeaders = options.client ? { [CANON_CLIENT_HEADER]: formatCanonClientHeader(options.client) } : {};
614
+ let clientUpdateRequired;
614
615
  const updateRequired = /* @__PURE__ */ __name((error) => {
615
- if (error.code === CLIENT_UPDATE_REQUIRED) try {
616
- options.onClientUpdateRequired?.(error);
617
- } catch {
616
+ if (error.code === CLIENT_UPDATE_REQUIRED) {
617
+ if (clientUpdateRequired) return clientUpdateRequired;
618
+ clientUpdateRequired = error;
619
+ try {
620
+ options.onClientUpdateRequired?.(error);
621
+ } catch {
622
+ }
618
623
  }
619
624
  return error;
620
625
  }, "updateRequired");
626
+ const assertClientSupported = /* @__PURE__ */ __name(() => {
627
+ if (clientUpdateRequired) throw clientUpdateRequired;
628
+ }, "assertClientSupported");
621
629
  const baseUrl = options.baseUrl.replace(/\/$/, "");
622
630
  let resolvedStreamId;
623
631
  function streamIdentity() {
@@ -639,7 +647,9 @@ function createHttpEndpointTransport(options) {
639
647
  __name(ownershipHeaders, "ownershipHeaders");
640
648
  async function call(path, method, body, signal, origin = baseUrl, groupResponse = false) {
641
649
  for (let authAttempt = 0; authAttempt < 2; authAttempt++) {
650
+ if (path !== "/endpoint/capabilities") assertClientSupported();
642
651
  const token = await options.credentials.getToken(authAttempt > 0);
652
+ if (path !== "/endpoint/capabilities") assertClientSupported();
643
653
  if (!token) throw new EndpointError("Authentication is required", { status: 401, code: "UNAUTHENTICATED", retryable: false });
644
654
  const controller = new AbortController();
645
655
  const abort = /* @__PURE__ */ __name(() => controller.abort(signal?.reason), "abort");
@@ -694,9 +704,12 @@ function createHttpEndpointTransport(options) {
694
704
  },
695
705
  ...options.streamUrl ? {
696
706
  async *events(streamOptions) {
707
+ assertClientSupported();
697
708
  const streamId = await streamIdentity();
698
709
  for (let attempt = 0; attempt < 2; attempt++) {
710
+ assertClientSupported();
699
711
  const token = await options.credentials.getToken(attempt > 0);
712
+ assertClientSupported();
700
713
  if (!token) throw new EndpointError("Authentication is required", { status: 401, code: "UNAUTHENTICATED", retryable: false });
701
714
  const connection = new AbortController();
702
715
  const abort = /* @__PURE__ */ __name(() => connection.abort(streamOptions.signal.reason), "abort");
@@ -717,7 +730,7 @@ function createHttpEndpointTransport(options) {
717
730
  await response.body?.cancel();
718
731
  continue;
719
732
  }
720
- if (!response.ok) throw updateRequired(await readHttpError(response, connection.signal));
733
+ if (!response.ok) throw await readHttpError(response, connection.signal);
721
734
  if (!response.headers.get("Content-Type")?.toLowerCase().startsWith("text/event-stream")) {
722
735
  await response.body?.cancel();
723
736
  throw new EndpointError("Canon returned an invalid event stream", { status: 502, code: "INVALID_EVENT_STREAM" });
@@ -732,6 +745,8 @@ function createHttpEndpointTransport(options) {
732
745
  yield event;
733
746
  }
734
747
  return;
748
+ } catch (error) {
749
+ throw error instanceof EndpointError ? updateRequired(error) : error;
735
750
  } finally {
736
751
  clearTimeout(handshake);
737
752
  streamOptions.signal.removeEventListener("abort", abort);
@@ -2,8 +2,8 @@ import {
2
2
  createMlsDevCredentialVerifier,
3
3
  mlsDevDeviceHttpConfiguration,
4
4
  parseMlsDevClientConfiguration
5
- } from "./chunk-QK37HAHC.js";
6
- import "./chunk-S7BV74DN.js";
5
+ } from "./chunk-YHDDOADK.js";
6
+ import "./chunk-5WPAB5MB.js";
7
7
  export {
8
8
  createMlsDevCredentialVerifier,
9
9
  mlsDevDeviceHttpConfiguration,
package/dist/cli.js CHANGED
@@ -23,11 +23,11 @@ import {
23
23
  runMlsDevSetup,
24
24
  startRelayChannel,
25
25
  writeRelayCredential
26
- } from "./chunks/chunk-DAJ7L7TN.js";
26
+ } from "./chunks/chunk-DNHJGAEL.js";
27
27
  import {
28
28
  assertPrivateHome,
29
29
  runnerLockName
30
- } from "./chunks/chunk-HH7KR22P.js";
30
+ } from "./chunks/chunk-DTAWEQCM.js";
31
31
  import {
32
32
  CanonApiError,
33
33
  CanonClient,
@@ -38,13 +38,13 @@ import {
38
38
  resolveCanonRuntimeConnection,
39
39
  runCli,
40
40
  verifyCanonRuntimeConnection
41
- } from "./chunks/chunk-5J4YPLNW.js";
42
- import "./chunks/chunk-FVYKLH6I.js";
43
- import "./chunks/chunk-QK37HAHC.js";
41
+ } from "./chunks/chunk-TYZT346O.js";
42
+ import "./chunks/chunk-YJUPKU47.js";
43
+ import "./chunks/chunk-YHDDOADK.js";
44
44
  import {
45
45
  __name,
46
46
  isCanonClientVersion
47
- } from "./chunks/chunk-S7BV74DN.js";
47
+ } from "./chunks/chunk-5WPAB5MB.js";
48
48
 
49
49
  // src/cli.ts
50
50
  import { realpathSync } from "node:fs";
@@ -89,29 +89,28 @@ Usage:
89
89
  canon-agent errands [--follow] [--cancel <errand id>] (--agent <id> | --profile <name>)
90
90
  [--environment <id>]
91
91
 
92
- Encrypted rooms need the agent's MLS device. The runner keeps it in $CANON_HOME and sets
93
- it up on the agent's first start: nothing to configure. On macOS (Apple silicon) and
94
- glibc Linux (x64, arm64) it uses the custody helper this package ships; on Windows,
95
- Intel Macs and musl Linux, this package's WASM core. Every run command also takes
96
- --mls-dev-config <path>, an operator's own custody instead. With none of these, the
97
- agent refuses encrypted rooms, and where Canon encrypts every new conversation it does
98
- not start.
92
+ Every room is encrypted, so the agent needs its MLS device. The runner keeps it in
93
+ $CANON_HOME and sets it up on the agent's first start: nothing to configure. On macOS
94
+ (Apple silicon) and glibc Linux (x64, arm64) it uses the custody helper this package
95
+ ships; on Windows, Intel Macs and musl Linux, this package's WASM core. Every run
96
+ command also takes --mls-dev-config <path>, an operator's own custody instead. With none
97
+ of these, the agent refuses every room, and where Canon encrypts every new conversation
98
+ it does not start.
99
99
 
100
100
  Team rooms (an owner's agents working together): claude, codex and acp also take
101
101
  [--instructions <file>] [--trust-agent <agentId>]...; every run command takes
102
- [--agent-turn-cap <n>] [--mention-alias <name>]..., which apply in encrypted rooms.
102
+ [--agent-turn-cap <n>] [--mention-alias <name>]....
103
103
  code, claude, codex and acp take [--allow-session-for-destructive] for encrypted cards.
104
104
 
105
105
  Errands: tell, post and errand direct a running agent from the machine it runs on:
106
106
  whoever can write $CANON_HOME commands it, and the CLI itself uses no network. tell
107
107
  leaves a private note for the agent's next turn in a room: never posted, it starts no
108
- turn. post sends the text as the agent's own message, with no turn (encrypted in an
109
- encrypted room). errand runs one owner-authorised turn that carries the instruction to
110
- the recipient (a room the agent is in, or a new conversation with a person or agent),
111
- reports to --origin, and tells later turns there why the agent came. What concerns an
112
- encrypted room is reported only to an encrypted origin; otherwise the report stays
113
- local (canon-agent errands). Canon's policies, blocks and rate limits apply as to any
114
- message from the agent.
108
+ turn. post sends the text, encrypted, as the agent's own message, with no turn. errand
109
+ runs one owner-authorised turn that carries the instruction to the recipient (a room
110
+ the agent is in, or a new conversation with a person or agent), reports to --origin,
111
+ and tells later turns there why the agent came. Without --origin the report stays local
112
+ (canon-agent errands). Canon's policies, blocks and rate limits apply as to any message
113
+ from the agent.
115
114
 
116
115
  Flags:
117
116
  --driver <name> The runtime driver: "code", "claude", "codex", "acp" or
@@ -152,19 +151,17 @@ Flags:
152
151
  as the owner's for tool use (repeat for several), only in a
153
152
  room whose other members are all listed agents that Canon
154
153
  confirms at each turn as active agents of this agent's
155
- owner (and, in plaintext, only for a final that agent's own
156
- runner marked as answering its owner). Otherwise they are
157
- guarded like any other agent's. Approvals still go to the
158
- owner.
159
- --agent-turn-cap <n> Encrypted rooms: another agent's message wakes this agent only
160
- when it @mentions it (by display name, id or an alias), at
161
- most n times in a row per room until a person writes there
162
- (default 6; 0: agents never wake it). Plaintext rooms
163
- follow Canon's group rules.
164
- --mention-alias <name> Encrypted rooms: another name that @mentions this agent, such
165
- as its role (repeat for several).
154
+ owner. Otherwise they are guarded like any other agent's.
155
+ Approvals still go to the owner.
156
+ --agent-turn-cap <n> Another agent's message wakes this agent only when it
157
+ @mentions it (by display name, id or an alias), at most n
158
+ times in a row per room until a person writes there
159
+ (default 6; 0: agents never wake it). The room's own
160
+ rules can stop them sooner.
161
+ --mention-alias <name> Another name that @mentions this agent, such as its role
162
+ (repeat for several).
166
163
  --allow-session-for-destructive
167
- Encrypted rooms: let the owner allow an action the runtime
164
+ Let the owner allow an action the runtime
168
165
  marks destructive (Claude Code's default-to-no prompts,
169
166
  Codex's risky commands and deletions) for the rest of the
170
167
  session. Off by default: each such action asks.
@@ -192,10 +189,9 @@ Flags:
192
189
  --text <text> tell: the note. post: the message. errand: the instruction.
193
190
  At most 32 KiB.
194
191
  --to <id> errand: a conversation the agent is in, or else a person or
195
- agent to start a new (plaintext) conversation with.
192
+ agent to start a new conversation with.
196
193
  --why <why> errand: why the owner sends the agent (at most 4 KiB).
197
- --origin <id> errand: the conversation the report goes to. A report about an
198
- encrypted recipient goes only to an encrypted origin.
194
+ --origin <id> errand: the conversation the report goes to.
199
195
  --follow errands: go on printing each change.
200
196
  --cancel <id> errands: cancel that errand (Stop in its origin also stops it).
201
197
  --agent <id> tell, post, errand, errands: the agent (or --profile).
@@ -24,7 +24,10 @@ export interface StdioRpcOptions {
24
24
  /** Sent on every message: `{ jsonrpc: '2.0' }` where the runtime's protocol requires it. */
25
25
  envelope?: Json;
26
26
  }
27
- /** JSON-RPC over a child's stdio: one line per message. A refusal rejects with the runtime's numeric `code`. */
27
+ /**
28
+ * JSON-RPC over a child's stdio: one line per message. A refusal rejects with the runtime's numeric `code`. A child that
29
+ * exits always reaches `close`, which otherwise waits for its pipes, so a driver can settle its process there.
30
+ */
28
31
  export declare function stdioRpc(child: ReturnType<typeof spawn>, handlers: {
29
32
  notify(method: string, params: Json): void;
30
33
  request(method: string, params: Json, id: unknown): Promise<unknown>;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { loadMlsDevConfiguration, MLS_SETUP_ACTIONS, mlsDevRoomPackageId, runMls
5
5
  export type { MlsSetupAction, RunnerMlsOptions } from './runner/mls.js';
6
6
  export { bundledMlsCustodyHelper, bundledMlsWasmCore, MLS_ENVIRONMENT_PINS, type BundledMlsWasmCore } from './runner/mls-bundled.js';
7
7
  export { managedMlsDevice, type ManagedMlsDevice, type ManagedMlsDeviceOptions } from './runner/mls-managed.js';
8
- export type { ActivityEvent, AskAnswer, AskRequest, DriverCapabilities, DriverResult, DriverState, DriverTurn, ErrandFacts, RuntimeDriver, ToolDefinition, ToolResult, TurnInput, TurnInputMessage, TurnTools, } from './runner/types.js';
8
+ export type { ActivityEvent, AskAnswer, AskRequest, DriverCapabilities, DriverResult, DriverState, DriverTurn, ErrandFacts, RoomFacts, RoomRules, RuntimeDriver, ToolDefinition, ToolResult, TurnInput, TurnInputMessage, TurnTools, } from './runner/types.js';
9
9
  export { errandJournal, errandsDirectory, queueErrand } from './runner/errands.js';
10
10
  export type { ErrandCommand, ErrandInput, ErrandKind, ErrandRecord, ErrandStatus } from './runner/errands.js';
11
11
  export { codeDriver } from './drivers/code.js';
package/dist/index.js CHANGED
@@ -24,8 +24,8 @@ import {
24
24
  runMlsDevSetup,
25
25
  runtimeDescriptor,
26
26
  startRelayChannel
27
- } from "./chunks/chunk-DAJ7L7TN.js";
28
- import "./chunks/chunk-HH7KR22P.js";
27
+ } from "./chunks/chunk-DNHJGAEL.js";
28
+ import "./chunks/chunk-DTAWEQCM.js";
29
29
  import {
30
30
  CanonApiError,
31
31
  DEFAULT_ANTHROPIC_REQUEST_HEADROOM_BYTES,
@@ -50,10 +50,10 @@ import {
50
50
  toAnthropicImageBlock,
51
51
  toAnthropicImageBlocksWithinBudget,
52
52
  uploadMediaFile
53
- } from "./chunks/chunk-5J4YPLNW.js";
54
- import "./chunks/chunk-FVYKLH6I.js";
55
- import "./chunks/chunk-QK37HAHC.js";
56
- import "./chunks/chunk-S7BV74DN.js";
53
+ } from "./chunks/chunk-TYZT346O.js";
54
+ import "./chunks/chunk-YJUPKU47.js";
55
+ import "./chunks/chunk-YHDDOADK.js";
56
+ import "./chunks/chunk-5WPAB5MB.js";
57
57
  export {
58
58
  CanonApiError,
59
59
  ConnectorRelayError,
@@ -288,6 +288,23 @@ export declare function parseMlsDevGroupCreateConversation(value: unknown): MlsD
288
288
  export declare function parseMlsDevGroupHead(value: unknown): MlsDevGroupHead;
289
289
  export declare function parseMlsDevGroupMarker(value: unknown): MlsDevGroupMarker;
290
290
  export declare function parseMlsDevGroupRoster(value: unknown): readonly MlsDevGroupRosterEntry[];
291
+ /** How long a room waits for a member who just joined it, or was there at its birth (D2, mls-rooms-by-default.md §2.7). */
292
+ export declare const MLS_MEMBER_JOIN_WAIT_MS = 60000;
293
+ /**
294
+ * Whom a send waits for in a room Canon made; empty means it may go (D2, narrowed 2026-10-31, mls-rooms-by-default.md
295
+ * §2.7). `unacceptedIds` are a direct request's target and founders still invited. `joinedAtMs` is the room's
296
+ * `mlsMemberJoinedAtMs`, NaN when it has none.
297
+ */
298
+ export declare function mlsAdmissionWait(input: {
299
+ senderId: string;
300
+ memberIds: readonly string[];
301
+ unacceptedIds: readonly string[];
302
+ admitted: {
303
+ has(id: string): boolean;
304
+ };
305
+ joinedAtMs: number;
306
+ nowMs: number;
307
+ }): string[];
291
308
  /** Hold, then close (owner ruling 2026-10-16; mls-dev-groups.md): how long an erased member's devices wait for a commit. */
292
309
  export declare const MLS_DEV_ROOM_REMOVAL_DEADLINE_MS: number;
293
310
  export interface MlsDevRoomRemovalEntry {
@@ -32,8 +32,3 @@ export declare function createCompletedOutputJournal<T extends CompletedOutputRe
32
32
  /** Runtime-specific shape check beyond the base fields; false is an invalid record. */
33
33
  validate?: (record: T) => boolean;
34
34
  }): CompletedOutputJournal<T>;
35
- /** A new delivery after restart must not silently adopt a changed audience. */
36
- export declare function assertCompletedOutputAudience(record: Pick<CompletedOutputRecordBase, 'audience'>, current: {
37
- memberIds: string[];
38
- membershipRevision?: number;
39
- } | null, label: string): void;
@@ -26,9 +26,6 @@ export type { RegistrationSession, RegistrationCredentials, RegistrationStore, R
26
26
  export { ensureAgentProfile } from './registration-profile.js';
27
27
  export type { EnsureAgentProfileOptions } from './registration-profile.js';
28
28
  export { submitRegistrationRequest, } from './registration.js';
29
- export { RuntimeRequestManager, RuntimeRequestCancelledError, runtimeInputDescriptor, runtimeCardDescriptor, runtimePlanDescriptor, } from './runtime-request-manager.js';
30
- export type { RuntimeRequestKind, RuntimeRequestContext, RuntimeRequestOptions, RuntimeConsumeOutcome, RuntimeOutcomeMessage, RuntimeRequestCallInput, RuntimeRequestPreflightInput, RuntimeRequestPushInput, RuntimeRequestPushMatch, KindDescriptor, RuntimeInputRequestPayload, RuntimeInputRequestResult, RuntimeCardRequestPayload, RuntimeCardRequestResult, RuntimePlanRequestPayload, RuntimePlanRequestResult, } from './runtime-request-manager.js';
31
- export { ApprovalManager } from './approval-manager.js';
32
29
  export { generateApprovalId, buildApprovalRequest, buildApprovalOutcome, redactSecrets, } from './approval-format.js';
33
30
  export { DEFAULT_APPROVAL_CONFIG, parseApprovalReplyMetadata, parseSessionRule, } from './approval-types.js';
34
31
  export type { ApprovalRequestCategory, ApprovalRequestDetail, ApprovalRequestMetadata, ApprovalNativeRequestMetadata, ApprovalRisk, ApprovalReplyMetadata, ApprovalOutcomeMetadata, SessionRule, ApprovalResult, ApprovalConfig, } from './approval-types.js';
@@ -37,10 +34,7 @@ export type { TruncateUnifiedDiffOptions } from './unified-diff.js';
37
34
  export { decodeStoredRuntimeCard } from '../backend-contracts/index.js';
38
35
  export { RUNTIME_CARD_SCHEMA_V1, RUNTIME_CARD_LIMITS, RUNTIME_CARD_FIELD_TYPES, RUNTIME_CARD_LINE_ITEM_COLUMN_TYPES, buildRuntimeCardOutcome, buildRuntimeCardPreview, buildRuntimeInputOutcome, parseRuntimeCardV1, validateRuntimeCardFieldValues, } from './runtime-cards.js';
39
36
  export type { PlanApprovalDecision, PlanApprovalMetadata, PlanApprovalReplyMetadata, RuntimeCardAction, RuntimeCardActionsBlock, RuntimeCardBlock, RuntimeCardBlockKind, RuntimeCardCalloutBlock, RuntimeCardChartBlock, RuntimeCardChartPoint, RuntimeCardChartSeries, RuntimeCardDetailsBlock, RuntimeCardDetailsRow, RuntimeCardField, RuntimeCardFieldChoice, RuntimeCardFieldType, RuntimeCardKnownBlockKind, RuntimeCardLineItemColumn, RuntimeCardLineItemColumnType, RuntimeCardListBlock, RuntimeCardListItem, RuntimeCardMediaKind, RuntimeCardMediaPreviewBlock, RuntimeCardMediaPreviewMedia, RuntimeCardMetric, RuntimeCardMetricGridBlock, RuntimeCardNativeMetadata, RuntimeCardOutcomeMetadata, RuntimeCardPreview, RuntimeCardReplyMetadata, RuntimeCardReplyStatus, RuntimeCardRequestMetadata, RuntimeCardResolutionStatus, RuntimeCardSchemaV1, RuntimeCardSummaryBlock, RuntimeCardTableBlock, RuntimeCardTone, RuntimeCardUnknownBlock, RuntimeCardV1, RuntimeInputAnswers, RuntimeInputChoice, RuntimeInputKind, RuntimeInputNativeMetadata, RuntimeInputOutcomeMetadata, RuntimeInputQuestion, RuntimeInputReplyMetadata, RuntimeInputReplyStatus, RuntimeInputRequestMetadata, RuntimeInputResolutionStatus, } from './runtime-cards.js';
40
- export { NO_REPLY_ACK_NOTE, NO_REPLY_REASON_SENTINEL, reportNoReplyOutcome, } from './silent-turn.js';
41
- export type { NoReplyReportClient } from './silent-turn.js';
42
- export { DEFAULT_TURN_VERBOSITY_BY_CONVERSATION_TYPE, normalizeTurnVerbosityConversationType, parseTurnVerbosityConfig, resolveTurnVerbosity, } from './turn-verbosity.js';
43
- export type { TurnVerbosity, TurnVerbosityConfig, TurnVerbosityConversationType, } from './turn-verbosity.js';
37
+ export { NO_REPLY_ACK_NOTE, NO_REPLY_REASON_SENTINEL, } from './silent-turn.js';
44
38
  export { clearPendingRegistration, loadPendingRegistrations, loadProfiles, savePendingRegistrations, saveProfiles, upsertAgentProfile, isProfileLocked, acquireLock, releaseLock, isProcessAlive, CANON_DIR, AGENTS_PATH, LOCKS_DIR, } from './agent-profiles.js';
45
39
  export type { AgentProfile, AgentProfileInput, PendingRegistration, ProfileLockHandle, } from './agent-profiles.js';
46
40
  export { initRTDBAuth, } from './rtdb-rest.js';
@@ -49,8 +43,8 @@ export { renderCanonHostInboundContent, } from './host-runtime.js';
49
43
  export type { CanonReplyContext, } from './host-runtime.js';
50
44
  export { createRuntimeStatePublisher, } from './runtime-state-publisher.js';
51
45
  export type { RuntimeStatePublisher, RuntimeStatePublisherOptions, RuntimeStreamingPayload, ClearRuntimeActivityOptions, } from './runtime-state-publisher.js';
52
- export { buildChunkedMessagePartMetadata, CANON_MESSAGE_TEXT_MAX_BYTES, ChunkedSendMessageError, DEFAULT_CHUNKED_MESSAGE_TEXT_MAX_BYTES, sendMessageWithRetryChunked, isPendingCanonOperation, isChunkedSendMessageError, isRetryableCanonDeliveryError, sendMessageWithRetry, splitTextByUtf8Bytes, utf8ByteLength, } from './retry.js';
53
- export type { ChunkedMessagePartMetadataInput, ChunkedSendMessageResult, SendMessageChunkingOptions, SendMessageRetryOptions, } from './retry.js';
46
+ export { buildChunkedMessagePartMetadata, CANON_MESSAGE_TEXT_MAX_BYTES, DEFAULT_CHUNKED_MESSAGE_TEXT_MAX_BYTES, isPendingCanonOperation, isRetryableCanonDeliveryError, splitTextByUtf8Bytes, splitTextWithinBytes, utf8ByteLength, } from './retry.js';
47
+ export type { ChunkedMessagePartMetadataInput, } from './retry.js';
54
48
  export { DEFAULT_BASE_URL } from './constants.js';
55
49
  export { CANON_RUNTIME_ENDPOINT_DEFAULTS, DEFAULT_CANON_ENVIRONMENT_ID, DEFAULT_CANON_RUNTIME_ENDPOINTS, getCanonRuntimeEndpointDefaults, requireCanonRuntimeEndpointDefaults, resolveCanonRuntimeConnection, verifyCanonRuntimeConnection, } from './runtime-endpoints.js';
56
50
  export type { CanonRuntimeConnection, CanonRuntimeConnectionOptions, CanonRuntimeEndpointDefaults, } from './runtime-endpoints.js';
@@ -1,82 +1,12 @@
1
- import type { SendMessageOptions } from './types.js';
2
- import { type CanonClient } from './client.js';
3
- export interface SendMessageRetryOptions {
4
- /** Stable replacement recorded by the product after a conclusive rejection. */
5
- operationId?: string;
6
- replacesOperationId?: string;
7
- signal?: AbortSignal;
8
- timeoutMs?: number;
9
- maxAttempts?: number;
10
- baseDelayMs?: number;
11
- maxDelayMs?: number;
12
- sleep?: (ms: number) => Promise<void>;
13
- }
14
1
  export declare const CANON_MESSAGE_TEXT_MAX_BYTES: number;
15
2
  export declare const DEFAULT_CHUNKED_MESSAGE_TEXT_MAX_BYTES = 3800;
16
- export interface SendMessageChunkingOptions {
17
- maxTextBytes?: number;
18
- /**
19
- * Opt in to resumable chunked delivery.
20
- *
21
- * With it on, a mid-sequence failure throws a `ChunkedSendMessageError`
22
- * carrying the ids of the parts that ARE durable, so a later attempt can pick
23
- * up the tail. Off by default so callers that do not resume keep today's
24
- * behaviour: the raw send error, unwrapped.
25
- *
26
- * Implied by a non-empty `deliveredMessageIds` — passing progress back IS
27
- * opting in.
28
- */
29
- resumable?: boolean;
30
- /**
31
- * Ids of the parts an earlier attempt already made durable, in part order.
32
- * Those parts are skipped and their ids are carried into the result, so a
33
- * resumed send still reports the whole answer.
34
- */
35
- deliveredMessageIds?: readonly string[];
36
- }
37
- export interface ChunkedSendMessageResult {
38
- messageIds: string[];
39
- }
40
3
  /** Pending delivery is visible, but cannot truthfully produce a failure notice. */
41
4
  export declare function isPendingCanonOperation(error: unknown): boolean;
42
- /**
43
- * A chunked send that stopped part-way, with the progress needed to resume it.
44
- *
45
- * Parts 1..`deliveredMessageIds.length` are durable in Canon; only the tail is
46
- * missing. Handing `deliveredMessageIds` back to `sendMessageWithRetryChunked`
47
- * restarts at the next part instead of re-sending the answer's head — which the
48
- * server would reject or duplicate, and which the reader has already seen.
49
- */
50
- export declare class ChunkedSendMessageError extends Error {
51
- /** Ids of the parts that are durable in Canon, in part order. */
52
- readonly deliveredMessageIds: string[];
53
- /** The part the send stopped on (1-based). */
54
- readonly failedPart: number;
55
- /** How many parts the text splits into in total. */
56
- readonly totalParts: number;
57
- /** The underlying send failure — what callers should classify. */
58
- readonly cause: unknown;
59
- constructor(input: {
60
- cause: unknown;
61
- deliveredMessageIds: readonly string[];
62
- failedPart: number;
63
- totalParts: number;
64
- });
65
- /** How many parts are durable — a resume starts at the next one. */
66
- get deliveredParts(): number;
67
- }
68
- /**
69
- * Structural check as well as `instanceof`, so progress survives a caller that
70
- * ended up with a second copy of this module (a workspace package resolved to
71
- * both `dist` and source, say) instead of silently degrading to "no progress".
72
- */
73
- export declare function isChunkedSendMessageError(error: unknown): error is ChunkedSendMessageError;
74
5
  export declare function isRetryableCanonDeliveryError(error: unknown): boolean;
75
- export declare function sendMessageWithRetry(client: CanonClient, conversationId: string, text: string, options?: SendMessageOptions, retryOptions?: SendMessageRetryOptions): Promise<{
76
- messageId: string;
77
- }>;
78
6
  export declare function utf8ByteLength(value: string): number;
79
7
  export declare function splitTextByUtf8Bytes(text: string, maxBytes?: number): string[];
8
+ /** The same split for a limit of the caller's own: an encrypted room's text takes up to 32 KiB. */
9
+ export declare function splitTextWithinBytes(text: string, byteLimit: number): string[];
80
10
  export declare function chunkMessageId(baseMessageId: string | undefined, index: number): string | undefined;
81
11
  export interface ChunkedMessagePartMetadataInput {
82
12
  /** Stable group id shared by every part, normally the unsuffixed message id. */
@@ -94,20 +24,3 @@ export interface ChunkedMessagePartMetadataInput {
94
24
  * preceding message parts.
95
25
  */
96
26
  export declare function buildChunkedMessagePartMetadata(input: ChunkedMessagePartMetadataInput): Record<string, unknown>;
97
- /**
98
- * Send `text` as one message, or as an ordered sequence of `-part-N` messages
99
- * when it exceeds the byte budget.
100
- *
101
- * Sequential by construction, so a failure leaves parts 1..k durable and the
102
- * tail unsent. Callers that opt into `resumable` get that progress back (see
103
- * `ChunkedSendMessageError`) and can hand it to a later attempt, which then
104
- * picks up at part k+1. The split is a pure function of the text and the byte
105
- * budget, so part N of a resumed attempt is byte-identical to part N of the
106
- * attempt that delivered it — which is what makes the `-part-N` ids a safe
107
- * resume cursor.
108
- *
109
- * A byte-identical replay succeeds at the server. Any idempotency conflict
110
- * therefore means the stored part differs and is always reported; treating it
111
- * as delivered would stitch two different answers together.
112
- */
113
- export declare function sendMessageWithRetryChunked(client: CanonClient, conversationId: string, text: string, options?: SendMessageOptions, retryOptions?: SendMessageRetryOptions, chunkingOptions?: SendMessageChunkingOptions): Promise<ChunkedSendMessageResult>;
@@ -11,39 +11,10 @@
11
11
  * the server and the hosts depend on.
12
12
  */
13
13
  export { NO_REPLY_ACK_NOTE } from '../backend-contracts/index.js';
14
- import { type CanonVerbWireRequest } from '../backend-contracts/index.js';
15
- /** The one client capability the outcome report needs. */
16
- export interface NoReplyReportClient {
17
- executeVerbWire(wire: CanonVerbWireRequest): Promise<unknown>;
18
- }
19
14
  /**
20
- * What `reportNoReplyOutcome` puts on the wire in place of any caller-supplied
21
- * reason text. The server stores only `hasReason` and discards the text, so
22
- * transmitting the model- or handler-authored sentence would be pure exposure:
23
- * the sentinel preserves the server's `hasReason` signal without moving the
24
- * text. The reason a binding was handed never leaves its process.
15
+ * What a `no_reply` verb carries in place of any caller-supplied reason text.
16
+ * The server stores only `hasReason` and discards the text, so transmitting
17
+ * the model- or handler-authored sentence would be pure exposure: the sentinel
18
+ * preserves the server's `hasReason` signal without moving the text.
25
19
  */
26
20
  export declare const NO_REPLY_REASON_SENTINEL = "given";
27
- /**
28
- * Report a locally-answered `no_reply` to the server, fire-and-forget.
29
- *
30
- * Four of the five runtimes answer the silence tool inside their own process
31
- * and never reach `POST /agent/verbs/no_reply`, so Canon's durable record of
32
- * deliberate silence (`/runtime-silence/{convoId}/{agentId}`) would otherwise
33
- * cover Claude turns only. This is telemetry, not behavior: the silence flag
34
- * is already set locally before this is called, so a failed or unreachable
35
- * report degrades to exactly the pre-report behavior — never to a posted
36
- * message and never to a failed turn.
37
- *
38
- * `params.reason` is read only for its presence: the wire carries
39
- * `NO_REPLY_REASON_SENTINEL` in its place, never the caller's text.
40
- *
41
- * The Claude host must NOT call this helper: its binding already POSTs the
42
- * verb via agent-tools, so calling both would double-record the silence.
43
- */
44
- export declare function reportNoReplyOutcome(client: NoReplyReportClient, params: {
45
- conversationId: string;
46
- messageId?: string;
47
- reason?: string;
48
- now?: number;
49
- }): void;
@@ -34,6 +34,9 @@ export interface EndpointExecuteOptions {
34
34
  operationId?: string;
35
35
  sensitive?: boolean;
36
36
  guardId?: string;
37
+ /** A person's text in an encrypted room that is held (D2): kept on this device and sent once the room may send, the
38
+ * call waiting with it, instead of refused with `MLS_DEV_GROUP_ADMISSION_PENDING`. */
39
+ waitWhileHeld?: boolean;
37
40
  }
38
41
  export interface EndpointWaitOptions {
39
42
  signal?: AbortSignal;
@@ -46,6 +46,8 @@ export interface MlsDevVerifiedMessageBinding {
46
46
  export interface MlsDevAdmissionHold {
47
47
  readonly held: boolean;
48
48
  readonly waitingPrincipalIds: readonly string[];
49
+ /** This device joined after the room's first message, so its history starts later (mls-rooms-by-default.md §2.7). */
50
+ readonly missedEarlier?: true;
49
51
  }
50
52
  export interface MlsDevCurrentAudience {
51
53
  readonly version: 1;
@@ -173,6 +175,16 @@ export declare function createMlsDevGroups(options: MlsDevDeviceClientOptions, c
173
175
  * encrypted room (mls-payload-v3.md §4). Items and cards are not forwarded yet. */
174
176
  forwardText(value: unknown, operationId: string, guardId?: string): Promise<EndpointOperation>;
175
177
  sendText(value: unknown, operationId: string, guardId?: string): Promise<EndpointOperation>;
178
+ /** `sendText` for a person's composer: in a held room the text is kept, not refused (undefined), until `sendHeldTexts`. */
179
+ holdText(value: unknown, operationId: string): Promise<EndpointOperation | undefined>;
180
+ sendHeldTexts(conversationId: string): Promise<{
181
+ sent: EndpointOperation[];
182
+ failed: {
183
+ operationId: string;
184
+ error: EndpointError;
185
+ }[];
186
+ waiting: boolean;
187
+ }>;
176
188
  /** A room this device holds caught up is read as it holds it: what fetches the room's new entries says so
177
189
  * (bridge.historyChanged). Otherwise a read fetches the feed first, which the polling fallback and the connected
178
190
  * stream's minute-long safety poll rely on. */
@@ -23,6 +23,35 @@ export declare const mlsDevOwnAnswerKey: (conversationId: string, agentId: strin
23
23
  /** Whether this device's answer to a card is committed and still on its way: queued, or its outcome uncertain, and not
24
24
  * yet applied from the feed (where the reduction takes over) nor refused. The card waits for it rather than answer twice. */
25
25
  export declare function isMlsDevOwnAnswerSending(tx: EndpointStoreTransaction, conversationId: string, agentId: string, requestId: string): Promise<boolean>;
26
+ /**
27
+ * A text its sender sent while the room was held (D2, mls-rooms-by-default.md §2.7): kept here, unencrypted and never in a
28
+ * request, until the hold lifts. Then it is encrypted and queued as any send, in the order sent, and this record goes.
29
+ */
30
+ export interface MlsDevHeldText {
31
+ version: 1;
32
+ /** The send's body as authored, its message ID fixed: what is encrypted once the room may send. */
33
+ body: {
34
+ conversationId: string;
35
+ messageId: string;
36
+ text: string;
37
+ replyTo?: string;
38
+ mentions?: string[];
39
+ };
40
+ operationId: string;
41
+ senderId: string;
42
+ senderType: 'human' | 'ai_agent';
43
+ createdAtMs: number;
44
+ /** The order sent, within the room's kept texts. */
45
+ sequence: number;
46
+ /** Refused for good when its turn came; kept so its sender sees it failed and can send it again. */
47
+ failed?: string;
48
+ }
49
+ export declare const mlsDevHeldTextPrefix: (conversationId?: string) => string;
50
+ export declare const mlsDevHeldTextKey: (conversationId: string, messageId: string) => string;
51
+ /** A room's held texts, oldest first. */
52
+ export declare function readMlsDevHeldTexts(tx: EndpointStoreTransaction, conversationId: string): Promise<MlsDevHeldText[]>;
53
+ /** Held texts per room. A send past it is refused, as a held send was before rooms kept them. */
54
+ export declare const MLS_DEV_HELD_TEXT_MAX = 100;
26
55
  /** A deletion for everyone that reached this device, before or after the message itself (mls-payload-v3.md §4). */
27
56
  export declare const mlsDevTextDeletedKey: (conversationId: string, messageId: string) => string;
28
57
  /** The reactions Canon holds for a message's public stub, which the history shows beside its decrypted text. */
@@ -58,6 +58,6 @@ export declare function createHttpEndpointTransport(options: {
58
58
  /** Names this client on every request and stream (`X-Canon-Client`), so Canon can apply its client floor. */
59
59
  client?: CanonClientIdentity;
60
60
  /** Canon refused this client as below its floor (`426 CLIENT_UPDATE_REQUIRED`), on any request or stream. Called
61
- * before the error is thrown, so a host can stop wherever the refusal surfaces. */
61
+ * once before the error is thrown; further operations, queries, publishes and streams are blocked, not capabilities. */
62
62
  onClientUpdateRequired?(error: EndpointError): void;
63
63
  }): EndpointTransport;
package/dist/media.js CHANGED
@@ -18,10 +18,10 @@ import {
18
18
  toAnthropicImageBlock,
19
19
  toAnthropicImageBlocksWithinBudget,
20
20
  uploadMediaFile
21
- } from "./chunks/chunk-5J4YPLNW.js";
22
- import "./chunks/chunk-FVYKLH6I.js";
23
- import "./chunks/chunk-QK37HAHC.js";
24
- import "./chunks/chunk-S7BV74DN.js";
21
+ } from "./chunks/chunk-TYZT346O.js";
22
+ import "./chunks/chunk-YJUPKU47.js";
23
+ import "./chunks/chunk-YHDDOADK.js";
24
+ import "./chunks/chunk-5WPAB5MB.js";
25
25
  export {
26
26
  DEFAULT_ANTHROPIC_REQUEST_HEADROOM_BYTES,
27
27
  DEFAULT_MEDIA_CACHE_DIR,
@@ -2,20 +2,20 @@ import {
2
2
  WASM_HOST_CONFIGURE,
3
3
  WASM_HOST_PROVISION,
4
4
  keyFile
5
- } from "./chunks/chunk-HH7KR22P.js";
5
+ } from "./chunks/chunk-DTAWEQCM.js";
6
6
  import {
7
7
  MAX_INPUT,
8
8
  NodeMlsDevCustodyError,
9
9
  parseFrame,
10
10
  rejected,
11
11
  requireValue
12
- } from "./chunks/chunk-FVYKLH6I.js";
12
+ } from "./chunks/chunk-YJUPKU47.js";
13
13
  import {
14
14
  __name,
15
15
  canonicalEndpointJson,
16
16
  isMlsDevReceiptClockSkew,
17
17
  parseMlsDevDeviceContext
18
- } from "./chunks/chunk-S7BV74DN.js";
18
+ } from "./chunks/chunk-5WPAB5MB.js";
19
19
 
20
20
  // src/mls-wasm-host.ts
21
21
  import { createHash } from "node:crypto";