@canonmsg/agent-sdk 10.2.1 → 10.4.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/README.md +17 -63
- package/dist/attached-session.d.ts +58 -0
- package/dist/attached-session.js +564 -0
- package/dist/canon-agent.d.ts +1 -0
- package/dist/canon-agent.js +81 -23
- package/dist/index.d.ts +8 -0
- package/dist/index.js +4 -0
- package/dist/media.d.ts +6 -0
- package/dist/media.js +4 -1
- package/dist/work-session-host.d.ts +31 -0
- package/dist/work-session-host.js +573 -0
- package/dist/work-session-interactions.d.ts +12 -0
- package/dist/work-session-interactions.js +173 -0
- package/dist/work-session-state.d.ts +36 -0
- package/dist/work-session-state.js +62 -0
- package/package.json +7 -3
package/dist/canon-agent.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApprovalManager, RuntimeRequestManager, runtimeInputDescriptor, runtimeCardDescriptor, CanonClient, ControlChannelPoller, buildCanonTurnContextV2, buildCanonGroupContext, buildParticipationHistorySnapshot, createTurnOutputController, createRuntimeStatePublisher, createRuntimeHeartbeat, createTypingStatusPublisher, diffCanonMemberIds, FINAL_MESSAGE_HANDOFF_MS, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeCardOutcome, buildRuntimeInputOutcome, initRTDBAuth, isChunkedSendMessageError, normalizeRuntimeCommandDescriptors, normalizeTurnMetadata, normalizeTurnVerbosityConversationType, reportNoReplyOutcome, resolveCanonReplyContext, resolveMessageActiveSelfContextId, resolveRuntimeProvenance, resolveTurnVerbosity, selectActiveSelfContexts, renderCanonHostInboundContent, resolveCanonRuntimeConnection, sendMessageWithRetryChunked, shouldPublishTurnTrail, splitTextByUtf8Bytes, verifyCanonRuntimeConnection, } from '@canonmsg/core';
|
|
1
|
+
import { ApprovalManager, RuntimeRequestManager, runtimeInputDescriptor, runtimeCardDescriptor, CanonClient, ControlChannelPoller, buildCanonTurnContextV2, buildCanonGroupContext, buildParticipationHistorySnapshot, createTurnOutputController, createRuntimeStatePublisher, createRuntimeHeartbeat, createTypingStatusPublisher, diffCanonMemberIds, FINAL_MESSAGE_HANDOFF_MS, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeCardOutcome, buildRuntimeInputOutcome, initRTDBAuth, isChunkedSendMessageError, normalizeRuntimeCommandDescriptors, normalizeTurnMetadata, normalizeTurnVerbosityConversationType, reportNoReplyOutcome, resolveCanonReplyContext, resolveMessageActiveSelfContextId, resolveRuntimeProvenance, resolveTurnVerbosity, resolveConversationPolicyScope, selectActiveSelfContexts, renderCanonHostInboundContent, resolveCanonRuntimeConnection, sendMessageWithRetryChunked, shouldPublishTurnTrail, splitTextByUtf8Bytes, verifyCanonRuntimeConnection, } from '@canonmsg/core';
|
|
2
2
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { Debouncer } from './debouncer.js';
|
|
4
4
|
import { DEFAULT_RUNTIME_INPUT_TIMEOUT_MS, RUNTIME_INPUT_ID_PATTERN, buildRuntimeCardCreateArgs, normalizeResponseUserId, resolveRuntimeCardRouting, } from './runtime-card.js';
|
|
@@ -143,6 +143,9 @@ const STANDARD_PRIMITIVE_COMMANDS = {
|
|
|
143
143
|
function sleep(ms) {
|
|
144
144
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
145
145
|
}
|
|
146
|
+
function knownMembershipRevision(value) {
|
|
147
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
148
|
+
}
|
|
146
149
|
function sleepWithAbort(ms, signal) {
|
|
147
150
|
if (signal.aborted)
|
|
148
151
|
return Promise.reject(createTurnAbortError());
|
|
@@ -325,6 +328,7 @@ export class CanonAgent {
|
|
|
325
328
|
activeAbortControllers = new Map();
|
|
326
329
|
activeTurns = new Map();
|
|
327
330
|
conversationMemberIds = new Map();
|
|
331
|
+
conversationMembershipRevisions = new Map();
|
|
328
332
|
pendingMembershipChanges = new Map();
|
|
329
333
|
typingSignals;
|
|
330
334
|
sseConnectedLogged = false;
|
|
@@ -964,24 +968,43 @@ export class CanonAgent {
|
|
|
964
968
|
}
|
|
965
969
|
rememberConversationMembers(conversations) {
|
|
966
970
|
for (const conversation of conversations) {
|
|
971
|
+
const revision = knownMembershipRevision(conversation.membershipRevision);
|
|
972
|
+
const currentRevision = this.conversationMembershipRevisions.get(conversation.id);
|
|
973
|
+
if (revision !== undefined && currentRevision !== undefined && revision < currentRevision)
|
|
974
|
+
continue;
|
|
967
975
|
this.conversationMemberIds.set(conversation.id, [...(conversation.memberIds ?? [])]);
|
|
976
|
+
if (revision !== undefined)
|
|
977
|
+
this.conversationMembershipRevisions.set(conversation.id, revision);
|
|
978
|
+
else
|
|
979
|
+
this.conversationMembershipRevisions.delete(conversation.id);
|
|
968
980
|
}
|
|
969
981
|
}
|
|
970
982
|
handleConversationUpdated(payload) {
|
|
971
983
|
const rawMemberIds = payload.changes.memberIds;
|
|
972
984
|
if (!Array.isArray(rawMemberIds))
|
|
973
985
|
return;
|
|
986
|
+
const revision = knownMembershipRevision(payload.changes.membershipRevision);
|
|
987
|
+
const currentRevision = this.conversationMembershipRevisions.get(payload.conversationId);
|
|
988
|
+
if (revision !== undefined && currentRevision !== undefined && revision < currentRevision)
|
|
989
|
+
return;
|
|
974
990
|
const memberIds = rawMemberIds.filter((id) => typeof id === 'string');
|
|
975
991
|
const hadPreviousMemberIds = this.conversationMemberIds.has(payload.conversationId);
|
|
976
992
|
const previousMemberIds = this.conversationMemberIds.get(payload.conversationId) ?? [];
|
|
977
993
|
const membershipChange = payload.membershipChange
|
|
978
994
|
?? (hadPreviousMemberIds ? diffCanonMemberIds(previousMemberIds, memberIds) : null);
|
|
979
995
|
this.conversationMemberIds.set(payload.conversationId, memberIds);
|
|
996
|
+
if (revision !== undefined)
|
|
997
|
+
this.conversationMembershipRevisions.set(payload.conversationId, revision);
|
|
998
|
+
else
|
|
999
|
+
this.conversationMembershipRevisions.delete(payload.conversationId);
|
|
980
1000
|
if (membershipChange) {
|
|
981
1001
|
this.pendingMembershipChanges.set(payload.conversationId, membershipChange);
|
|
982
1002
|
}
|
|
983
1003
|
if (this.agentId && !memberIds.includes(this.agentId)) {
|
|
984
1004
|
this.cachedConversationIds = this.cachedConversationIds.filter((id) => id !== payload.conversationId);
|
|
1005
|
+
this.abortActiveTurns(payload.conversationId);
|
|
1006
|
+
this.sessionManager?.dropQueued(payload.conversationId);
|
|
1007
|
+
this.pendingMembershipChanges.delete(payload.conversationId);
|
|
985
1008
|
}
|
|
986
1009
|
else {
|
|
987
1010
|
this.rememberConversationId(payload.conversationId);
|
|
@@ -1254,7 +1277,53 @@ export class CanonAgent {
|
|
|
1254
1277
|
async executeHandler(conversationId, messages, session, provenanceByMessageId) {
|
|
1255
1278
|
if (!this.handler)
|
|
1256
1279
|
return;
|
|
1280
|
+
// Message rediscovery can precede the SSE roster snapshot after admission.
|
|
1281
|
+
// Refresh before trusting cached exclusion, accepting queued input, or
|
|
1282
|
+
// freezing output policy. Reuse this same snapshot for handler context.
|
|
1283
|
+
let membersBeforeRefresh = this.conversationMemberIds.get(conversationId);
|
|
1284
|
+
let conversations;
|
|
1285
|
+
try {
|
|
1286
|
+
conversations = await this.apiClient.getConversations();
|
|
1287
|
+
}
|
|
1288
|
+
catch {
|
|
1289
|
+
// Realtime delivery has already deduplicated these IDs. Retry this read
|
|
1290
|
+
// here once; throwing does not arrange replay or requeue the input.
|
|
1291
|
+
await sleep(100);
|
|
1292
|
+
membersBeforeRefresh = this.conversationMemberIds.get(conversationId);
|
|
1293
|
+
try {
|
|
1294
|
+
conversations = await this.apiClient.getConversations();
|
|
1295
|
+
}
|
|
1296
|
+
catch (error) {
|
|
1297
|
+
console.error(`[canon-sdk] Pre-turn conversation refresh failed for ${conversationId}:`, error);
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
let conversation = conversations.find((c) => c.id === conversationId);
|
|
1302
|
+
if (!conversation)
|
|
1303
|
+
return;
|
|
1304
|
+
const membersDuringRefresh = this.conversationMemberIds.get(conversationId);
|
|
1305
|
+
const currentRevision = this.conversationMembershipRevisions.get(conversationId);
|
|
1306
|
+
const refreshedRevision = knownMembershipRevision(conversation.membershipRevision);
|
|
1307
|
+
const comparableRevisions = currentRevision !== undefined && refreshedRevision !== undefined;
|
|
1308
|
+
const keepCachedRoster = comparableRevisions
|
|
1309
|
+
? currentRevision > refreshedRevision
|
|
1310
|
+
: membersDuringRefresh !== membersBeforeRefresh;
|
|
1311
|
+
if (membersDuringRefresh && keepCachedRoster) {
|
|
1312
|
+
// Prefer the higher known revision. For legacy unversioned snapshots,
|
|
1313
|
+
// retain an event received while the request was pending.
|
|
1314
|
+
conversation = { ...conversation, memberIds: membersDuringRefresh, membershipRevision: currentRevision };
|
|
1315
|
+
}
|
|
1316
|
+
else {
|
|
1317
|
+
this.rememberConversationMembers([conversation]);
|
|
1318
|
+
}
|
|
1319
|
+
const currentMembers = this.conversationMemberIds.get(conversationId);
|
|
1320
|
+
if (currentMembers && this.agentId && !currentMembers.includes(this.agentId))
|
|
1321
|
+
return;
|
|
1322
|
+
this.rememberConversationId(conversationId);
|
|
1257
1323
|
await this.markQueuedMessagesAccepted(conversationId, messages);
|
|
1324
|
+
const acceptedMembers = this.conversationMemberIds.get(conversationId);
|
|
1325
|
+
if (acceptedMembers && this.agentId && !acceptedMembers.includes(this.agentId))
|
|
1326
|
+
return;
|
|
1258
1327
|
const turnId = randomUUID();
|
|
1259
1328
|
const turnOpenedAt = Date.now();
|
|
1260
1329
|
let turnState = 'thinking';
|
|
@@ -1316,19 +1385,14 @@ export class CanonAgent {
|
|
|
1316
1385
|
: {}),
|
|
1317
1386
|
})).catch(() => { });
|
|
1318
1387
|
};
|
|
1319
|
-
//
|
|
1320
|
-
//
|
|
1321
|
-
//
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
// before the first publish of any kind.
|
|
1328
|
-
//
|
|
1329
|
-
// Re-deriving it mid-turn is what must never happen: a turn that started
|
|
1330
|
-
// quiet and finished verbose would emit a trail nothing narrated.
|
|
1331
|
-
const inboundConversationType = normalizeTurnVerbosityConversationType(provenanceByMessageId?.get(triggeringMessageId ?? '')?.conversation?.type);
|
|
1388
|
+
// Resolve once from the refreshed roster before constructing the output
|
|
1389
|
+
// controller or publishing the first thinking seed. Keep it fixed for the
|
|
1390
|
+
// turn so the final trail agrees with what was actually narrated.
|
|
1391
|
+
const inboundProvenance = provenanceByMessageId?.get(triggeringMessageId ?? '')?.conversation;
|
|
1392
|
+
const inboundRoster = this.conversationMemberIds.get(conversationId) ?? inboundProvenance?.memberCount;
|
|
1393
|
+
const inboundConversationType = inboundRoster != null
|
|
1394
|
+
? resolveConversationPolicyScope(inboundRoster)
|
|
1395
|
+
: normalizeTurnVerbosityConversationType(inboundProvenance?.type);
|
|
1332
1396
|
const turnVerbosity = resolveTurnVerbosity({
|
|
1333
1397
|
configured: selectConfiguredTurnVerbosity(this.options.turnVerbosity, inboundConversationType),
|
|
1334
1398
|
conversationType: inboundConversationType,
|
|
@@ -1412,12 +1476,6 @@ export class CanonAgent {
|
|
|
1412
1476
|
if (this.sessionManager && session) {
|
|
1413
1477
|
this.sessionManager.seedHistory(conversationId, history);
|
|
1414
1478
|
}
|
|
1415
|
-
// Get conversation info
|
|
1416
|
-
const conversations = await this.apiClient.getConversations();
|
|
1417
|
-
this.rememberConversationMembers(conversations);
|
|
1418
|
-
const conversation = conversations.find((c) => c.id === conversationId);
|
|
1419
|
-
if (!conversation)
|
|
1420
|
-
return;
|
|
1421
1479
|
// Build reply functions
|
|
1422
1480
|
const replyFinal = async (text, options) => {
|
|
1423
1481
|
throwIfAborted();
|
|
@@ -1615,7 +1673,7 @@ export class CanonAgent {
|
|
|
1615
1673
|
? resolveRuntimeProvenance({
|
|
1616
1674
|
provenance: provenanceByMessageId?.get(latestMessage.id) ?? null,
|
|
1617
1675
|
conversationId,
|
|
1618
|
-
conversationType: conversation.
|
|
1676
|
+
conversationType: resolveConversationPolicyScope(conversation.memberIds),
|
|
1619
1677
|
memberCount: conversation.memberIds.length,
|
|
1620
1678
|
senderId: latestMessage.senderId,
|
|
1621
1679
|
senderName: latestMessage.senderName ?? latestMessage.senderId,
|
|
@@ -1628,7 +1686,7 @@ export class CanonAgent {
|
|
|
1628
1686
|
})
|
|
1629
1687
|
: resolveRuntimeProvenance({
|
|
1630
1688
|
conversationId,
|
|
1631
|
-
conversationType: conversation.
|
|
1689
|
+
conversationType: resolveConversationPolicyScope(conversation.memberIds),
|
|
1632
1690
|
memberCount: conversation.memberIds.length,
|
|
1633
1691
|
senderId: '',
|
|
1634
1692
|
senderType: 'human',
|
|
@@ -1663,7 +1721,7 @@ export class CanonAgent {
|
|
|
1663
1721
|
content: latestMessage ? renderCanonHostInboundContent(latestMessage) : '[Empty message]',
|
|
1664
1722
|
conversationId,
|
|
1665
1723
|
participantContext: {
|
|
1666
|
-
conversationType: conversation.
|
|
1724
|
+
conversationType: resolveConversationPolicyScope(conversation.memberIds),
|
|
1667
1725
|
memberCount: conversation.memberIds.length,
|
|
1668
1726
|
senderType: latestMessage?.senderType ?? provenance.sender.type,
|
|
1669
1727
|
senderName: latestMessage?.senderName
|
package/dist/index.d.ts
CHANGED
|
@@ -11,3 +11,11 @@ export type { SessionConfig, Session } from './session-manager.js';
|
|
|
11
11
|
export type { CanonAgentTurnVerbosityOption } from './turn-verbosity-option.js';
|
|
12
12
|
export type { AgentContext, CanonGroupContext, CanonKnownRecentParticipant, CanonMembershipChange, CanonMessage, CanonConversation, CommunicateInput, CommunicateResult, DirectConversationSelection, CanonConversationsPage, CanonConversationsPageOptions, CanonReplyContext, CanonSelfContext, CanonTurnContextV2, CanonRuntimeDescriptor, MessageUpdatedPayload, SendMessageOptions, CreateGroupOptions, CreateGroupResult, TurnVerbosity, TurnVerbosityConfig, } from '@canonmsg/core';
|
|
13
13
|
export type { CanonAgentConnectionOptions, CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, FinalMessageResult, MessageHandler, MessageHandlerContext, MessageUpdatedHandler, ParticipationSuppressedHandler, ProgressMessageOptions, ProgressMessageResult, RuntimeApprovalRequest, RuntimeInputRequest, RuntimeInputResult, RuntimePlanReviewRequest, RuntimePlanReviewResult, RuntimeControlSurface, RuntimePrimitiveContext, RuntimePrimitiveHandler, RuntimePrimitiveHandlers, SessionInfo, SessionOptions, DeliveryMode, } from './types.js';
|
|
14
|
+
export { createCanonAttachedSession, createCanonAttachedSessionPublisher } from './attached-session.js';
|
|
15
|
+
export { createCanonWorkSessionHost } from './work-session-host.js';
|
|
16
|
+
export type { CanonWorkSessionHost, CanonWorkSessionHostOptions } from './work-session-host.js';
|
|
17
|
+
export { createFileWorkSessionHostStore } from './work-session-state.js';
|
|
18
|
+
export type { WorkSessionHostStore, WorkSessionHostJournal } from './work-session-state.js';
|
|
19
|
+
export { createFileAttachedSessionStore } from '@canonmsg/core';
|
|
20
|
+
export type { CanonAttachedSession, CanonAttachedSessionConnection, CanonAttachedSessionOptions, CanonAttachedSessionStatus, } from './attached-session.js';
|
|
21
|
+
export type { AttachedNativeSessionAdapter, AttachedSessionBinding, AttachedSessionJournal, AttachedSessionState, AttachedSessionStore, NativeSessionEvent, NativeSessionItem, NativeSessionSnapshot, NativeSubmissionResult, } from '@canonmsg/core';
|
package/dist/index.js
CHANGED
|
@@ -3,3 +3,7 @@ export { clearPendingRegistration, ensureAgentProfile, resumeRegistration } from
|
|
|
3
3
|
export { ApprovalManager, buildApprovalOutcome, buildApprovalReply, buildApprovalRequest, CanonApiError, DEFAULT_APPROVAL_CONFIG, generateApprovalId, HOST_ADMISSION_ACTION_CAPABILITIES, HOST_ADMISSION_ACTIONS_DISABLED, parseApprovalReplyMetadata, parseApprovalRequestMetadata, parseSessionRule, redactSecrets, } from '@canonmsg/core';
|
|
4
4
|
export { SessionManager } from './session-manager.js';
|
|
5
5
|
export { DEFAULT_ANTHROPIC_REQUEST_HEADROOM_BYTES, DEFAULT_MEDIA_CACHE_DIR, DEFAULT_MEDIA_MATERIALIZATION_BYTES, MAX_ANTHROPIC_IMAGE_RAW_BYTES, MAX_ANTHROPIC_REQUEST_BYTES, MAX_CANON_MEDIA_BYTES, getCodexImagePath, getMessageAttachments, inferUploadMimeType, isAnthropicImageAttachment, materializeAttachment, materializeMessageMedia, materializeReplyContextMedia, resolveAttachmentMimeType, sendMediaFileMessage, toAnthropicImageBlock, toAnthropicImageBlocksWithinBudget, uploadMediaFile, } from './media.js';
|
|
6
|
+
export { createCanonAttachedSession, createCanonAttachedSessionPublisher } from './attached-session.js';
|
|
7
|
+
export { createCanonWorkSessionHost } from './work-session-host.js';
|
|
8
|
+
export { createFileWorkSessionHostStore } from './work-session-state.js';
|
|
9
|
+
export { createFileAttachedSessionStore } from '@canonmsg/core';
|
package/dist/media.d.ts
CHANGED
|
@@ -22,6 +22,12 @@ export interface UploadMediaFileOptions {
|
|
|
22
22
|
signal?: AbortSignal;
|
|
23
23
|
}
|
|
24
24
|
export interface ReplyWithFileOptions extends Omit<SendMessageOptions, 'attachments' | 'contentType'>, UploadMediaFileOptions {
|
|
25
|
+
/**
|
|
26
|
+
* Optional local policy check after upload/finalization, immediately before
|
|
27
|
+
* publishing the attachment. Returning false withholds the message. Automatic
|
|
28
|
+
* artifact routing uses this to recheck its current audience.
|
|
29
|
+
*/
|
|
30
|
+
canPublish?: () => boolean;
|
|
25
31
|
}
|
|
26
32
|
export interface MaterializedCanonAttachment extends MediaAttachment {
|
|
27
33
|
index: number;
|
package/dist/media.js
CHANGED
|
@@ -396,7 +396,7 @@ export async function uploadMediaFile(client, conversationId, filePath, options)
|
|
|
396
396
|
return uploaded;
|
|
397
397
|
}
|
|
398
398
|
export async function sendMediaFileMessage(client, conversationId, filePath, text = '', options) {
|
|
399
|
-
const { fileName, mimeType, durationMs, fetchImpl, signal, ...sendOptions } = options ?? {};
|
|
399
|
+
const { fileName, mimeType, durationMs, fetchImpl, signal, canPublish, ...sendOptions } = options ?? {};
|
|
400
400
|
const uploaded = await uploadMediaFile(client, conversationId, filePath, {
|
|
401
401
|
...(fileName ? { fileName } : {}),
|
|
402
402
|
...(mimeType ? { mimeType } : {}),
|
|
@@ -405,6 +405,9 @@ export async function sendMediaFileMessage(client, conversationId, filePath, tex
|
|
|
405
405
|
...(signal ? { signal } : {}),
|
|
406
406
|
});
|
|
407
407
|
signal?.throwIfAborted();
|
|
408
|
+
if (canPublish && !canPublish()) {
|
|
409
|
+
throw new Error('Canon media publication withheld by current routing policy');
|
|
410
|
+
}
|
|
408
411
|
return client.sendMessage(conversationId, text, {
|
|
409
412
|
...sendOptions,
|
|
410
413
|
contentType: uploaded.attachment.kind,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type AttachedSessionBinding, type AttachedSessionStore, type NativeWorkSessionProvider } from '@canonmsg/core';
|
|
2
|
+
import { type CanonAttachedSessionConnection, type CanonAttachedSessionStatus } from './attached-session.js';
|
|
3
|
+
import { type WorkSessionHostStore } from './work-session-state.js';
|
|
4
|
+
export interface CanonWorkSessionHostOptions {
|
|
5
|
+
connection: CanonAttachedSessionConnection;
|
|
6
|
+
/** Stable installation identity. A new random runtime epoch is used each start. */
|
|
7
|
+
hostId: string;
|
|
8
|
+
displayName: string;
|
|
9
|
+
provider: NativeWorkSessionProvider;
|
|
10
|
+
store: WorkSessionHostStore;
|
|
11
|
+
createSessionStore(binding: AttachedSessionBinding): AttachedSessionStore;
|
|
12
|
+
/** Process-wide native audience lock, shared with any standalone attachment CLI. */
|
|
13
|
+
acquireNativeSession(binding: AttachedSessionBinding): (() => void) | Promise<() => void>;
|
|
14
|
+
onStatus?: (event: {
|
|
15
|
+
status: 'available' | 'stopped' | 'session';
|
|
16
|
+
conversationId?: string;
|
|
17
|
+
session?: CanonAttachedSessionStatus;
|
|
18
|
+
}) => void;
|
|
19
|
+
onError?: (error: unknown, operation: string) => void;
|
|
20
|
+
pollIntervalMs?: number;
|
|
21
|
+
heartbeatIntervalMs?: number;
|
|
22
|
+
connectTimeoutMs?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface CanonWorkSessionHost {
|
|
25
|
+
start(): Promise<void>;
|
|
26
|
+
stop(): Promise<void>;
|
|
27
|
+
/** Refresh discovery and process one durable request; serialized with the poll loop. */
|
|
28
|
+
reconcile(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/** One authenticated transport and liveness publisher, with durable per-room native routes. */
|
|
31
|
+
export declare function createCanonWorkSessionHost(options: CanonWorkSessionHostOptions): CanonWorkSessionHost;
|