@canonmsg/agent-sdk 3.2.2 → 3.2.4

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.
@@ -910,9 +910,10 @@ export class CanonAgent {
910
910
  }
911
911
  async handleRuntimePrimitiveEvent(event) {
912
912
  // Requests only belong to this runtime once primitive handlers exist —
913
- // leave them untouched otherwise (the legacy loop never read the key).
913
+ // defer otherwise: the request stays in RTDB AND unseen, so a handler
914
+ // registered via onPrimitive() after start still receives it.
914
915
  if (!this.hasRuntimePrimitiveSupport())
915
- return { consume: false };
916
+ return { defer: true };
916
917
  const { conversationId, requestId, value } = event;
917
918
  const primitive = value.id;
918
919
  // Unknown primitives and unhandled ids fall through so the poller
@@ -935,10 +936,11 @@ export class CanonAgent {
935
936
  });
936
937
  }
937
938
  async handleRuntimeSignalEvent(event) {
938
- // Signals only belong to this runtime once signal handlers exist — leave
939
- // them untouched otherwise (the legacy loop never read the key).
939
+ // Signals only belong to this runtime once signal handlers exist — defer
940
+ // otherwise: the signal stays in RTDB AND unseen, so a handler registered
941
+ // via on('interrupt' | ...) after start still receives it.
940
942
  if (!this.hasRuntimeSignalSupport())
941
- return { consume: false };
943
+ return { defer: true };
942
944
  const { conversationId, type: signal, updatedAt } = event;
943
945
  const handler = signal === 'new_session'
944
946
  ? this.newSessionHandler
@@ -19,6 +19,7 @@ export declare class RealtimeManager {
19
19
  /** Lower bound for catch-up in conversations with no in-memory cursor. */
20
20
  private readonly replaySyncStartedAt;
21
21
  private replayCatchupInFlight;
22
+ private hasConnectedOnce;
22
23
  private lastSseErrorKey;
23
24
  private lastSseErrorAt;
24
25
  private suppressedSseErrorCount;
@@ -33,6 +34,7 @@ export declare class RealtimeManager {
33
34
  private onConnected;
34
35
  private onDisconnected;
35
36
  constructor(apiKey: string, debouncer: Debouncer, agentId: string, streamUrl?: string, apiClient?: CanonClient);
37
+ private queueReplayCatchup;
36
38
  private hasSeenInboundMessage;
37
39
  private recordSeenInboundMessage;
38
40
  private pruneRecentInboundMessageIds;
package/dist/realtime.js CHANGED
@@ -34,6 +34,7 @@ export class RealtimeManager {
34
34
  /** Lower bound for catch-up in conversations with no in-memory cursor. */
35
35
  replaySyncStartedAt = Date.now();
36
36
  replayCatchupInFlight = null;
37
+ hasConnectedOnce = false;
37
38
  lastSseErrorKey = null;
38
39
  lastSseErrorAt = 0;
39
40
  suppressedSseErrorCount = 0;
@@ -122,16 +123,19 @@ export class RealtimeManager {
122
123
  },
123
124
  onConnected: () => {
124
125
  // Reset backoff is handled internally by CanonStream
126
+ const shouldCatchUp = this.hasConnectedOnce;
127
+ this.hasConnectedOnce = true;
125
128
  this.onConnected?.();
129
+ if (shouldCatchUp) {
130
+ this.queueReplayCatchup();
131
+ }
126
132
  },
127
133
  onDisconnected: () => {
128
134
  this.onDisconnected?.();
129
135
  },
130
136
  onReplayExpired: (payload) => {
131
137
  console.error(`[canon-sdk] SSE replay window expired${payload.lastAvailableId ? ` (oldest available event: ${payload.lastAvailableId})` : ''} — catching up over REST`);
132
- this.replayCatchupInFlight ??= this.runReplayCatchup().finally(() => {
133
- this.replayCatchupInFlight = null;
134
- });
138
+ this.queueReplayCatchup();
135
139
  },
136
140
  onError: (err) => {
137
141
  this.logSseError(err);
@@ -139,6 +143,11 @@ export class RealtimeManager {
139
143
  },
140
144
  });
141
145
  }
146
+ queueReplayCatchup() {
147
+ this.replayCatchupInFlight ??= this.runReplayCatchup().finally(() => {
148
+ this.replayCatchupInFlight = null;
149
+ });
150
+ }
142
151
  hasSeenInboundMessage(conversationId, messageId) {
143
152
  return this.recentInboundMessageIds.has(`${conversationId}:${messageId}`);
144
153
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/agent-sdk",
3
- "version": "3.2.2",
3
+ "version": "3.2.4",
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": "^2.4.1"
31
+ "@canonmsg/core": "^2.6.0"
32
32
  },
33
33
  "publishConfig": {
34
34
  "access": "public"