@canonmsg/agent-sdk 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/dist/canon-agent.d.ts +5 -0
- package/dist/canon-agent.js +39 -2
- package/dist/polling.d.ts +3 -1
- package/dist/polling.js +8 -1
- package/dist/realtime.d.ts +6 -0
- package/dist/realtime.js +11 -0
- package/package.json +2 -2
package/dist/canon-agent.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare class CanonAgent {
|
|
|
12
12
|
private agentContext;
|
|
13
13
|
private cachedConversationIds;
|
|
14
14
|
private running;
|
|
15
|
+
private runtimeHeartbeatTimer;
|
|
15
16
|
constructor(options: CanonAgentOptions);
|
|
16
17
|
on(event: 'message', handler: MessageHandler): void;
|
|
17
18
|
start(): Promise<void>;
|
|
@@ -28,6 +29,10 @@ export declare class CanonAgent {
|
|
|
28
29
|
attachment: import('@canonmsg/core').MediaAttachment;
|
|
29
30
|
}>;
|
|
30
31
|
stop(): Promise<void>;
|
|
32
|
+
private publishAgentRuntime;
|
|
33
|
+
private startRuntimeHeartbeat;
|
|
34
|
+
private stopRuntimeHeartbeat;
|
|
35
|
+
private clearAgentRuntime;
|
|
31
36
|
private handleMessages;
|
|
32
37
|
private executeHandler;
|
|
33
38
|
static register(options: {
|
package/dist/canon-agent.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { CanonClient, FINAL_MESSAGE_HANDOFF_MS, initRTDBAuth, writeSessionState, clearSessionState, writeTurnState, clearTurnState, } from '@canonmsg/core';
|
|
1
|
+
import { CanonClient, FINAL_MESSAGE_HANDOFF_MS, initRTDBAuth, rtdbWrite, writeSessionState, clearSessionState, writeTurnState, clearTurnState, } from '@canonmsg/core';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { AuthManager } from './auth.js';
|
|
4
4
|
import { Debouncer } from './debouncer.js';
|
|
5
5
|
import { PollingManager } from './polling.js';
|
|
6
6
|
import { SessionManager } from './session-manager.js';
|
|
7
7
|
const AUTO_MODE_THRESHOLD = 500;
|
|
8
|
+
const AGENT_RUNTIME_HEARTBEAT_MS = 30_000;
|
|
8
9
|
const SDK_RUNTIME_CAPABILITIES = {
|
|
9
10
|
supportsInterrupt: false,
|
|
10
11
|
supportsQueue: true,
|
|
@@ -28,6 +29,7 @@ export class CanonAgent {
|
|
|
28
29
|
agentContext = null;
|
|
29
30
|
cachedConversationIds = [];
|
|
30
31
|
running = false;
|
|
32
|
+
runtimeHeartbeatTimer = null;
|
|
31
33
|
constructor(options) {
|
|
32
34
|
this.options = {
|
|
33
35
|
baseUrl: 'https://api-6m6mlelskq-uc.a.run.app',
|
|
@@ -109,12 +111,16 @@ export class CanonAgent {
|
|
|
109
111
|
rtm.setOnAgentContext((ctx) => {
|
|
110
112
|
this.agentContext = ctx;
|
|
111
113
|
});
|
|
114
|
+
rtm.setConnectionHandlers({
|
|
115
|
+
onConnected: () => this.startRuntimeHeartbeat(),
|
|
116
|
+
onDisconnected: () => this.stopRuntimeHeartbeat(),
|
|
117
|
+
});
|
|
112
118
|
this.realtimeManager = rtm;
|
|
113
119
|
await rtm.start();
|
|
114
120
|
console.log('[canon-sdk] SSE stream started');
|
|
115
121
|
}
|
|
116
122
|
else {
|
|
117
|
-
this.pollingManager = new PollingManager(this.apiClient, this.debouncer, agentId, this.options.pollingIntervalMs);
|
|
123
|
+
this.pollingManager = new PollingManager(this.apiClient, this.debouncer, agentId, this.options.pollingIntervalMs, () => this.startRuntimeHeartbeat(), () => this.stopRuntimeHeartbeat());
|
|
118
124
|
await this.pollingManager.start();
|
|
119
125
|
console.log(`[canon-sdk] Polling started (interval: ${this.options.pollingIntervalMs}ms)`);
|
|
120
126
|
}
|
|
@@ -155,6 +161,7 @@ export class CanonAgent {
|
|
|
155
161
|
clearTurnState(id, this.agentId).catch(() => { });
|
|
156
162
|
}
|
|
157
163
|
}
|
|
164
|
+
await this.clearAgentRuntime();
|
|
158
165
|
this.pollingManager?.stop();
|
|
159
166
|
this.realtimeManager?.stop();
|
|
160
167
|
this.sessionManager?.destroy();
|
|
@@ -162,6 +169,36 @@ export class CanonAgent {
|
|
|
162
169
|
this.debouncer.destroy();
|
|
163
170
|
console.log('[canon-sdk] Stopped');
|
|
164
171
|
}
|
|
172
|
+
async publishAgentRuntime() {
|
|
173
|
+
if (!this.agentId)
|
|
174
|
+
return;
|
|
175
|
+
await rtdbWrite(`/agent-runtime/${this.agentId}`, {
|
|
176
|
+
clientType: this.options.clientType ?? 'generic',
|
|
177
|
+
hostMode: false,
|
|
178
|
+
updatedAt: { '.sv': 'timestamp' },
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
startRuntimeHeartbeat() {
|
|
182
|
+
void this.publishAgentRuntime();
|
|
183
|
+
if (this.runtimeHeartbeatTimer)
|
|
184
|
+
return;
|
|
185
|
+
this.runtimeHeartbeatTimer = setInterval(() => {
|
|
186
|
+
void this.publishAgentRuntime();
|
|
187
|
+
}, AGENT_RUNTIME_HEARTBEAT_MS);
|
|
188
|
+
this.runtimeHeartbeatTimer.unref?.();
|
|
189
|
+
}
|
|
190
|
+
stopRuntimeHeartbeat() {
|
|
191
|
+
if (this.runtimeHeartbeatTimer) {
|
|
192
|
+
clearInterval(this.runtimeHeartbeatTimer);
|
|
193
|
+
this.runtimeHeartbeatTimer = null;
|
|
194
|
+
}
|
|
195
|
+
void this.clearAgentRuntime();
|
|
196
|
+
}
|
|
197
|
+
async clearAgentRuntime() {
|
|
198
|
+
if (!this.agentId)
|
|
199
|
+
return;
|
|
200
|
+
await rtdbWrite(`/agent-runtime/${this.agentId}`, null).catch(() => { });
|
|
201
|
+
}
|
|
165
202
|
async handleMessages(conversationId, messages) {
|
|
166
203
|
if (!this.handler) {
|
|
167
204
|
console.warn(`[canon-sdk] No message handler registered — messages for ${conversationId} dropped. Call agent.on('message', handler) before starting.`);
|
package/dist/polling.d.ts
CHANGED
|
@@ -5,10 +5,12 @@ export declare class PollingManager {
|
|
|
5
5
|
private debouncer;
|
|
6
6
|
private agentId;
|
|
7
7
|
private pollingIntervalMs;
|
|
8
|
+
private onHealthy;
|
|
9
|
+
private onUnhealthy;
|
|
8
10
|
private lastSeenTimestamps;
|
|
9
11
|
private pollTimer;
|
|
10
12
|
private running;
|
|
11
|
-
constructor(apiClient: CanonClient, debouncer: Debouncer, agentId: string, pollingIntervalMs: number);
|
|
13
|
+
constructor(apiClient: CanonClient, debouncer: Debouncer, agentId: string, pollingIntervalMs: number, onHealthy?: () => void, onUnhealthy?: () => void);
|
|
12
14
|
start(): Promise<void>;
|
|
13
15
|
private poll;
|
|
14
16
|
private findActiveConversations;
|
package/dist/polling.js
CHANGED
|
@@ -5,14 +5,18 @@ export class PollingManager {
|
|
|
5
5
|
debouncer;
|
|
6
6
|
agentId;
|
|
7
7
|
pollingIntervalMs;
|
|
8
|
+
onHealthy;
|
|
9
|
+
onUnhealthy;
|
|
8
10
|
lastSeenTimestamps = new Map();
|
|
9
11
|
pollTimer = null;
|
|
10
12
|
running = false;
|
|
11
|
-
constructor(apiClient, debouncer, agentId, pollingIntervalMs) {
|
|
13
|
+
constructor(apiClient, debouncer, agentId, pollingIntervalMs, onHealthy, onUnhealthy) {
|
|
12
14
|
this.apiClient = apiClient;
|
|
13
15
|
this.debouncer = debouncer;
|
|
14
16
|
this.agentId = agentId;
|
|
15
17
|
this.pollingIntervalMs = pollingIntervalMs;
|
|
18
|
+
this.onHealthy = onHealthy ?? null;
|
|
19
|
+
this.onUnhealthy = onUnhealthy ?? null;
|
|
16
20
|
}
|
|
17
21
|
async start() {
|
|
18
22
|
this.running = true;
|
|
@@ -22,6 +26,7 @@ export class PollingManager {
|
|
|
22
26
|
for (const convo of conversations) {
|
|
23
27
|
this.lastSeenTimestamps.set(convo.id, now);
|
|
24
28
|
}
|
|
29
|
+
this.onHealthy?.();
|
|
25
30
|
// Start polling
|
|
26
31
|
this.pollTimer = setInterval(() => this.poll(), this.pollingIntervalMs);
|
|
27
32
|
}
|
|
@@ -30,6 +35,7 @@ export class PollingManager {
|
|
|
30
35
|
return;
|
|
31
36
|
try {
|
|
32
37
|
const conversations = await this.apiClient.getConversations();
|
|
38
|
+
this.onHealthy?.();
|
|
33
39
|
const activeConvos = this.findActiveConversations(conversations);
|
|
34
40
|
await Promise.all(activeConvos.map(async (convo) => {
|
|
35
41
|
try {
|
|
@@ -67,6 +73,7 @@ export class PollingManager {
|
|
|
67
73
|
}));
|
|
68
74
|
}
|
|
69
75
|
catch (err) {
|
|
76
|
+
this.onUnhealthy?.();
|
|
70
77
|
console.error('[canon-sdk] Polling error:', err);
|
|
71
78
|
}
|
|
72
79
|
}
|
package/dist/realtime.d.ts
CHANGED
|
@@ -15,8 +15,14 @@ export declare class RealtimeManager {
|
|
|
15
15
|
private knownConversationIds;
|
|
16
16
|
private discoveryTimer;
|
|
17
17
|
private onAgentContext;
|
|
18
|
+
private onConnected;
|
|
19
|
+
private onDisconnected;
|
|
18
20
|
constructor(apiKey: string, debouncer: Debouncer, agentId: string, streamUrl?: string, apiClient?: CanonClient);
|
|
19
21
|
setOnAgentContext(cb: (ctx: AgentContext) => void): void;
|
|
22
|
+
setConnectionHandlers(handlers: {
|
|
23
|
+
onConnected?: () => void;
|
|
24
|
+
onDisconnected?: () => void;
|
|
25
|
+
}): void;
|
|
20
26
|
start(): Promise<void>;
|
|
21
27
|
stop(): void;
|
|
22
28
|
private discoverNewConversations;
|
package/dist/realtime.js
CHANGED
|
@@ -17,6 +17,8 @@ export class RealtimeManager {
|
|
|
17
17
|
knownConversationIds = new Set();
|
|
18
18
|
discoveryTimer = null;
|
|
19
19
|
onAgentContext = null;
|
|
20
|
+
onConnected = null;
|
|
21
|
+
onDisconnected = null;
|
|
20
22
|
constructor(apiKey, debouncer, agentId, streamUrl, apiClient) {
|
|
21
23
|
this.debouncer = debouncer;
|
|
22
24
|
this.agentId = agentId;
|
|
@@ -54,6 +56,10 @@ export class RealtimeManager {
|
|
|
54
56
|
},
|
|
55
57
|
onConnected: () => {
|
|
56
58
|
// Reset backoff is handled internally by CanonStream
|
|
59
|
+
this.onConnected?.();
|
|
60
|
+
},
|
|
61
|
+
onDisconnected: () => {
|
|
62
|
+
this.onDisconnected?.();
|
|
57
63
|
},
|
|
58
64
|
onError: (err) => {
|
|
59
65
|
console.error('[canon-sdk] SSE error:', err.message);
|
|
@@ -64,6 +70,10 @@ export class RealtimeManager {
|
|
|
64
70
|
setOnAgentContext(cb) {
|
|
65
71
|
this.onAgentContext = cb;
|
|
66
72
|
}
|
|
73
|
+
setConnectionHandlers(handlers) {
|
|
74
|
+
this.onConnected = handlers.onConnected ?? null;
|
|
75
|
+
this.onDisconnected = handlers.onDisconnected ?? null;
|
|
76
|
+
}
|
|
67
77
|
async start() {
|
|
68
78
|
this.running = true;
|
|
69
79
|
// Snapshot current conversations
|
|
@@ -89,6 +99,7 @@ export class RealtimeManager {
|
|
|
89
99
|
this.discoveryTimer = null;
|
|
90
100
|
}
|
|
91
101
|
this.stream.stop();
|
|
102
|
+
this.onDisconnected?.();
|
|
92
103
|
}
|
|
93
104
|
// ── Conversation discovery ─────────────────────────────────────────
|
|
94
105
|
async discoverNewConversations() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"node": ">=18.0.0"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@canonmsg/core": "^0.
|
|
26
|
+
"@canonmsg/core": "^0.5.0"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|