@canonmsg/agent-sdk 7.0.1 → 7.1.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/dist/canon-agent.d.ts +17 -1
- package/dist/canon-agent.js +59 -1
- package/dist/realtime.d.ts +10 -2
- package/dist/realtime.js +22 -1
- package/package.json +2 -2
package/dist/canon-agent.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AddMemberResult, type CanonContact, type CanonConversation, type CreateConversationResult, type CanonRuntimeActivityItem, type CanonRuntimeCommandDescriptor, type CanonRuntimeFact, type CanonRuntimePrimitiveId, type ContactCardPayload, type ClearRuntimeActivityOptions, type CreateContactRequestResult } from '@canonmsg/core';
|
|
1
|
+
import { type AddMemberResult, type CanonContact, type CanonConversation, type CreateConversationResult, type CanonRuntimeActivityItem, type CanonRuntimeCommandDescriptor, type CanonRuntimeFact, type CanonRuntimePrimitiveId, type ContactCardPayload, type ClearRuntimeActivityOptions, type CreateContactRequestResult, type CanonVoiceSession, type CanonVoiceSessionToken, type CreateVoiceSessionOptions, type VoiceSessionEventPayload } from '@canonmsg/core';
|
|
2
2
|
import type { CanonAgentConnectionOptions, CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, CreateConversationOptions, MessageHandler, MessageUpdatedHandler, ReachOutOptions, ReachOutResult, ContactRequestHandler, RuntimeSignalHandler, RuntimePrimitiveHandler } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Contact-graph operations exposed under `agent.contacts`. Wraps the REST
|
|
@@ -40,6 +40,10 @@ export declare class CanonAgent {
|
|
|
40
40
|
private interruptHandler;
|
|
41
41
|
private stopAndDropHandler;
|
|
42
42
|
private newSessionHandler;
|
|
43
|
+
private callStartedHandler;
|
|
44
|
+
private callEndedHandler;
|
|
45
|
+
/** Whether the live SSE stream was opened with the voice family attached. */
|
|
46
|
+
private voiceEventsEnabled;
|
|
43
47
|
private readonly primitiveHandlers;
|
|
44
48
|
private primitiveFallbackHandler;
|
|
45
49
|
/** Contact-graph operations (`agent.contacts.*`). Initialized in the constructor. */
|
|
@@ -96,6 +100,8 @@ export declare class CanonAgent {
|
|
|
96
100
|
on(event: 'interrupt', handler: RuntimeSignalHandler): void;
|
|
97
101
|
on(event: 'stopAndDrop', handler: RuntimeSignalHandler): void;
|
|
98
102
|
on(event: 'newSession', handler: RuntimeSignalHandler): void;
|
|
103
|
+
on(event: 'callStarted', handler: (payload: VoiceSessionEventPayload) => void | Promise<void>): void;
|
|
104
|
+
on(event: 'callEnded', handler: (payload: VoiceSessionEventPayload) => void | Promise<void>): void;
|
|
99
105
|
onPrimitive(primitive: CanonRuntimePrimitiveId | '*', handler: RuntimePrimitiveHandler): void;
|
|
100
106
|
describeCommands(_provider?: string): ReadonlyArray<CanonRuntimeCommandDescriptor>;
|
|
101
107
|
publishRuntimeFacts(conversationId: string, facts: ReadonlyArray<CanonRuntimeFact>): Promise<void>;
|
|
@@ -112,6 +118,16 @@ export declare class CanonAgent {
|
|
|
112
118
|
private executeReachOut;
|
|
113
119
|
start(): Promise<void>;
|
|
114
120
|
createConversation(options: CreateConversationOptions): Promise<CreateConversationResult>;
|
|
121
|
+
/** Start (or rejoin) a call in a conversation and get the room token. */
|
|
122
|
+
startCall(options: CreateVoiceSessionOptions): Promise<CanonVoiceSessionToken>;
|
|
123
|
+
/** Join an active call session and get the room token. */
|
|
124
|
+
joinCall(conversationId: string, sessionId: string): Promise<CanonVoiceSessionToken>;
|
|
125
|
+
/** Decline an incoming call: stops this agent's ring only. */
|
|
126
|
+
declineCall(conversationId: string, sessionId: string): Promise<void>;
|
|
127
|
+
/** End an active call session for everyone. */
|
|
128
|
+
endCall(conversationId: string, sessionId: string): Promise<void>;
|
|
129
|
+
/** Fetch the current state of a call session. */
|
|
130
|
+
getCallState(conversationId: string, sessionId: string): Promise<CanonVoiceSession>;
|
|
115
131
|
updateTopic(conversationId: string, topic: string): Promise<void>;
|
|
116
132
|
leaveConversation(conversationId: string): Promise<void>;
|
|
117
133
|
updateConversationName(conversationId: string, name: string): Promise<void>;
|
package/dist/canon-agent.js
CHANGED
|
@@ -257,6 +257,10 @@ export class CanonAgent {
|
|
|
257
257
|
interruptHandler = null;
|
|
258
258
|
stopAndDropHandler = null;
|
|
259
259
|
newSessionHandler = null;
|
|
260
|
+
callStartedHandler = null;
|
|
261
|
+
callEndedHandler = null;
|
|
262
|
+
/** Whether the live SSE stream was opened with the voice family attached. */
|
|
263
|
+
voiceEventsEnabled = false;
|
|
260
264
|
primitiveHandlers = new Map();
|
|
261
265
|
primitiveFallbackHandler = null;
|
|
262
266
|
/** Contact-graph operations (`agent.contacts.*`). Initialized in the constructor. */
|
|
@@ -426,6 +430,20 @@ export class CanonAgent {
|
|
|
426
430
|
});
|
|
427
431
|
}
|
|
428
432
|
on(event, handler) {
|
|
433
|
+
if (event === 'callStarted' || event === 'callEnded') {
|
|
434
|
+
// The voice SSE family is negotiated at connect from handler presence,
|
|
435
|
+
// so call handlers registered after start() would never fire.
|
|
436
|
+
if (this.running && !this.voiceEventsEnabled) {
|
|
437
|
+
console.warn('[canon-sdk] on(%s) registered after connect: the voice event family was not requested at stream start, so call events will not arrive until the agent restarts. Register call handlers before start().', event);
|
|
438
|
+
}
|
|
439
|
+
if (event === 'callStarted') {
|
|
440
|
+
this.callStartedHandler = handler;
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
this.callEndedHandler = handler;
|
|
444
|
+
}
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
429
447
|
if (event === 'message') {
|
|
430
448
|
this.handler = handler;
|
|
431
449
|
return;
|
|
@@ -656,7 +674,22 @@ export class CanonAgent {
|
|
|
656
674
|
this.startRuntimeControlPolling();
|
|
657
675
|
// 4. Start delivery
|
|
658
676
|
const { RealtimeManager } = await import('./realtime.js');
|
|
659
|
-
|
|
677
|
+
this.voiceEventsEnabled = Boolean(this.callStartedHandler || this.callEndedHandler);
|
|
678
|
+
const rtm = new RealtimeManager(this.options.apiKey, this.debouncer, agentId, this.options.streamUrl, this.apiClient, { enableVoiceEvents: this.voiceEventsEnabled });
|
|
679
|
+
if (this.voiceEventsEnabled) {
|
|
680
|
+
rtm.setCallHandlers({
|
|
681
|
+
onCallStarted: (payload) => {
|
|
682
|
+
void Promise.resolve(this.callStartedHandler?.(payload)).catch((error) => {
|
|
683
|
+
console.error('[canon-sdk] callStarted handler failed:', error);
|
|
684
|
+
});
|
|
685
|
+
},
|
|
686
|
+
onCallEnded: (payload) => {
|
|
687
|
+
void Promise.resolve(this.callEndedHandler?.(payload)).catch((error) => {
|
|
688
|
+
console.error('[canon-sdk] callEnded handler failed:', error);
|
|
689
|
+
});
|
|
690
|
+
},
|
|
691
|
+
});
|
|
692
|
+
}
|
|
660
693
|
rtm.setOnAgentContext((ctx) => {
|
|
661
694
|
this.agentContext = ctx;
|
|
662
695
|
this.ensureApprovalManager(ctx);
|
|
@@ -702,6 +735,31 @@ export class CanonAgent {
|
|
|
702
735
|
async createConversation(options) {
|
|
703
736
|
return this.apiClient.createConversation(options);
|
|
704
737
|
}
|
|
738
|
+
// ── Calls ────────────────────────────────────────────────────────────
|
|
739
|
+
// These return the LiveKit room token payload; the agent brings its own
|
|
740
|
+
// RTC transport (e.g. @livekit/rtc-node as an optional, lazily imported
|
|
741
|
+
// dependency — the openclaw voice bridge is the reference implementation).
|
|
742
|
+
/** Start (or rejoin) a call in a conversation and get the room token. */
|
|
743
|
+
async startCall(options) {
|
|
744
|
+
return this.apiClient.createVoiceSession(options);
|
|
745
|
+
}
|
|
746
|
+
/** Join an active call session and get the room token. */
|
|
747
|
+
async joinCall(conversationId, sessionId) {
|
|
748
|
+
return this.apiClient.joinVoiceSession(conversationId, sessionId);
|
|
749
|
+
}
|
|
750
|
+
/** Decline an incoming call: stops this agent's ring only. */
|
|
751
|
+
async declineCall(conversationId, sessionId) {
|
|
752
|
+
return this.apiClient.declineVoiceSession(conversationId, sessionId);
|
|
753
|
+
}
|
|
754
|
+
/** End an active call session for everyone. */
|
|
755
|
+
async endCall(conversationId, sessionId) {
|
|
756
|
+
return this.apiClient.endVoiceSession(conversationId, sessionId);
|
|
757
|
+
}
|
|
758
|
+
/** Fetch the current state of a call session. */
|
|
759
|
+
async getCallState(conversationId, sessionId) {
|
|
760
|
+
const result = await this.apiClient.getVoiceSessionState(conversationId, sessionId);
|
|
761
|
+
return result.session;
|
|
762
|
+
}
|
|
705
763
|
async updateTopic(conversationId, topic) {
|
|
706
764
|
return this.apiClient.updateTopic(conversationId, topic);
|
|
707
765
|
}
|
package/dist/realtime.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AgentContext, type CanonClient, type ContactAddedPayload, type ContactApprovedPayload, type ContactRemovedPayload, type ContactRequestPayload, type ConversationUpdatedPayload, type MessageUpdatedPayload } from '@canonmsg/core';
|
|
1
|
+
import { type AgentContext, type CanonClient, type ContactAddedPayload, type ContactApprovedPayload, type ContactRemovedPayload, type ContactRequestPayload, type ConversationUpdatedPayload, type MessageUpdatedPayload, type VoiceSessionEventPayload } from '@canonmsg/core';
|
|
2
2
|
import { Debouncer } from './debouncer.js';
|
|
3
3
|
/**
|
|
4
4
|
* Wraps @canonmsg/core's CanonStream with SDK-specific features:
|
|
@@ -26,7 +26,11 @@ export declare class RealtimeManager {
|
|
|
26
26
|
private onMessageDeleted;
|
|
27
27
|
private onConnected;
|
|
28
28
|
private onDisconnected;
|
|
29
|
-
|
|
29
|
+
private onCallStarted;
|
|
30
|
+
private onCallEnded;
|
|
31
|
+
constructor(apiKey: string, debouncer: Debouncer, agentId: string, streamUrl?: string, apiClient?: CanonClient, options?: {
|
|
32
|
+
enableVoiceEvents?: boolean;
|
|
33
|
+
});
|
|
30
34
|
private hasSeenInboundMessage;
|
|
31
35
|
private recordSeenInboundMessage;
|
|
32
36
|
private pruneRecentInboundMessageIds;
|
|
@@ -50,6 +54,10 @@ export declare class RealtimeManager {
|
|
|
50
54
|
onConnected?: () => void;
|
|
51
55
|
onDisconnected?: () => void;
|
|
52
56
|
}): void;
|
|
57
|
+
setCallHandlers(handlers: {
|
|
58
|
+
onCallStarted?: (payload: VoiceSessionEventPayload) => void;
|
|
59
|
+
onCallEnded?: (payload: VoiceSessionEventPayload) => void;
|
|
60
|
+
}): void;
|
|
53
61
|
start(): Promise<void>;
|
|
54
62
|
stop(): void;
|
|
55
63
|
}
|
package/dist/realtime.js
CHANGED
|
@@ -33,7 +33,9 @@ export class RealtimeManager {
|
|
|
33
33
|
onMessageDeleted = null;
|
|
34
34
|
onConnected = null;
|
|
35
35
|
onDisconnected = null;
|
|
36
|
-
|
|
36
|
+
onCallStarted = null;
|
|
37
|
+
onCallEnded = null;
|
|
38
|
+
constructor(apiKey, debouncer, agentId, streamUrl, apiClient, options) {
|
|
37
39
|
this.debouncer = debouncer;
|
|
38
40
|
this.agentId = agentId;
|
|
39
41
|
this.stream = new CanonStream({
|
|
@@ -41,6 +43,21 @@ export class RealtimeManager {
|
|
|
41
43
|
agentId,
|
|
42
44
|
streamUrl,
|
|
43
45
|
handler: {
|
|
46
|
+
// The voice family is requested from handler PRESENCE at stream
|
|
47
|
+
// construction, so these delegating closures exist only when the
|
|
48
|
+
// agent registered call handlers before connect — otherwise every
|
|
49
|
+
// SDK agent would cost the stream service a per-conversation
|
|
50
|
+
// voiceSessions listener for nothing.
|
|
51
|
+
...(options?.enableVoiceEvents
|
|
52
|
+
? {
|
|
53
|
+
onVoiceSessionStarted: (payload) => {
|
|
54
|
+
this.onCallStarted?.(payload);
|
|
55
|
+
},
|
|
56
|
+
onVoiceSessionEnded: (payload) => {
|
|
57
|
+
this.onCallEnded?.(payload);
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
: {}),
|
|
44
61
|
onMessage: (payload) => {
|
|
45
62
|
// Cross-flush id dedupe: SSE replay overlap must never double-fire
|
|
46
63
|
// a turn for the same message.
|
|
@@ -183,6 +200,10 @@ export class RealtimeManager {
|
|
|
183
200
|
this.onConnected = handlers.onConnected ?? null;
|
|
184
201
|
this.onDisconnected = handlers.onDisconnected ?? null;
|
|
185
202
|
}
|
|
203
|
+
setCallHandlers(handlers) {
|
|
204
|
+
this.onCallStarted = handlers.onCallStarted ?? null;
|
|
205
|
+
this.onCallEnded = handlers.onCallEnded ?? null;
|
|
206
|
+
}
|
|
186
207
|
async start() {
|
|
187
208
|
this.running = true;
|
|
188
209
|
await this.stream.start();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/agent-sdk",
|
|
3
|
-
"version": "7.0
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "Canon Agent SDK — build AI agents that participate in Canon conversations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"node": ">=18.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@canonmsg/core": "^7.0
|
|
31
|
+
"@canonmsg/core": "^7.1.0"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|