@canonmsg/agent-sdk 1.5.0 → 1.5.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.
@@ -116,6 +116,7 @@ export declare class CanonAgent {
116
116
  private hasRuntimeSignalSupport;
117
117
  private hasRuntimePrimitiveSupport;
118
118
  private hasRuntimeControlSupport;
119
+ private supportsInputInterrupt;
119
120
  private buildRuntimeDescriptor;
120
121
  private buildRuntimeCapabilities;
121
122
  private publishAgentRuntime;
@@ -9,6 +9,7 @@ const RUNTIME_PRIMITIVE_DEDUPE_TTL_MS = 5 * 60 * 1000;
9
9
  const RUNTIME_PRIMITIVE_DEDUPE_MAX = 1_000;
10
10
  const SDK_RUNTIME_CAPABILITIES = {
11
11
  supportsInterrupt: false,
12
+ supportsInputInterrupt: false,
12
13
  supportsQueue: true,
13
14
  supportsInterleave: false,
14
15
  supportsRequiresAction: true,
@@ -528,6 +529,9 @@ export class CanonAgent {
528
529
  rtm.setConversationUpdatedHandler((payload) => {
529
530
  this.handleConversationUpdated(payload);
530
531
  });
532
+ rtm.setMessageDeletedHandler((payload) => {
533
+ this.sessionManager?.dropQueuedMessage(payload.conversationId, payload.messageId);
534
+ });
531
535
  rtm.setConnectionHandlers({
532
536
  onConnected: () => this.startRuntimeHeartbeat(),
533
537
  onDisconnected: () => this.stopRuntimeHeartbeat(),
@@ -633,6 +637,9 @@ export class CanonAgent {
633
637
  hasRuntimeControlSupport() {
634
638
  return this.hasRuntimeSignalSupport() || this.hasRuntimePrimitiveSupport();
635
639
  }
640
+ supportsInputInterrupt() {
641
+ return this.hasInterruptSupport() && this.options.runtimeDescriptor?.supportsInputInterrupt !== false;
642
+ }
636
643
  buildRuntimeDescriptor() {
637
644
  const source = this.options.runtimeDescriptor ?? DEFAULT_SDK_RUNTIME_DESCRIPTOR;
638
645
  const hasInterrupt = this.hasInterruptSupport();
@@ -677,6 +684,7 @@ export class CanonAgent {
677
684
  return {
678
685
  ...source,
679
686
  supportsInterrupt: hasInterrupt,
687
+ supportsInputInterrupt: source.supportsInputInterrupt === false ? false : hasInterrupt,
680
688
  commands,
681
689
  actions,
682
690
  };
@@ -685,6 +693,7 @@ export class CanonAgent {
685
693
  return {
686
694
  ...SDK_RUNTIME_CAPABILITIES,
687
695
  supportsInterrupt: this.hasInterruptSupport(),
696
+ supportsInputInterrupt: this.supportsInputInterrupt(),
688
697
  supportsQueue: Boolean(this.sessionManager),
689
698
  };
690
699
  }
@@ -9,6 +9,7 @@ export declare class Debouncer {
9
9
  constructor(debounceMs: number);
10
10
  setCallback(cb: (conversationId: string, messages: CanonMessage[], provenanceByMessageId: ReadonlyMap<string, CanonRuntimeProvenance>) => void): void;
11
11
  add(conversationId: string, message: CanonMessage, provenance?: CanonRuntimeProvenance | null): void;
12
+ removeMessage(conversationId: string, messageId: string): boolean;
12
13
  private flush;
13
14
  destroy(): void;
14
15
  }
package/dist/debouncer.js CHANGED
@@ -43,6 +43,27 @@ export class Debouncer {
43
43
  this.flush(conversationId);
44
44
  }, this.debounceMs));
45
45
  }
46
+ removeMessage(conversationId, messageId) {
47
+ const existing = this.pending.get(conversationId);
48
+ if (!existing || existing.length === 0)
49
+ return false;
50
+ const next = existing.filter((message) => message.id !== messageId);
51
+ if (next.length === existing.length)
52
+ return false;
53
+ this.provenanceByMessageId.delete(messageId);
54
+ if (next.length === 0) {
55
+ this.pending.delete(conversationId);
56
+ this.orderedFlags.delete(conversationId);
57
+ const timer = this.timers.get(conversationId);
58
+ if (timer)
59
+ clearTimeout(timer);
60
+ this.timers.delete(conversationId);
61
+ }
62
+ else {
63
+ this.pending.set(conversationId, next);
64
+ }
65
+ return true;
66
+ }
46
67
  flush(conversationId) {
47
68
  const messages = this.pending.get(conversationId);
48
69
  const isOrdered = this.orderedFlags.get(conversationId) ?? false;
@@ -16,6 +16,7 @@ export declare class RealtimeManager {
16
16
  private onContactAdded;
17
17
  private onContactRemoved;
18
18
  private onConversationUpdated;
19
+ private onMessageDeleted;
19
20
  private onConnected;
20
21
  private onDisconnected;
21
22
  constructor(apiKey: string, debouncer: Debouncer, agentId: string, streamUrl?: string, apiClient?: CanonClient);
@@ -29,6 +30,10 @@ export declare class RealtimeManager {
29
30
  onContactRemoved?: (payload: ContactRemovedPayload) => void;
30
31
  }): void;
31
32
  setConversationUpdatedHandler(cb: (payload: ConversationUpdatedPayload) => void): void;
33
+ setMessageDeletedHandler(cb: (payload: {
34
+ conversationId: string;
35
+ messageId: string;
36
+ }) => void): void;
32
37
  setConnectionHandlers(handlers: {
33
38
  onConnected?: () => void;
34
39
  onDisconnected?: () => void;
package/dist/realtime.js CHANGED
@@ -15,6 +15,7 @@ export class RealtimeManager {
15
15
  onContactAdded = null;
16
16
  onContactRemoved = null;
17
17
  onConversationUpdated = null;
18
+ onMessageDeleted = null;
18
19
  onConnected = null;
19
20
  onDisconnected = null;
20
21
  constructor(apiKey, debouncer, agentId, streamUrl, apiClient) {
@@ -54,6 +55,10 @@ export class RealtimeManager {
54
55
  };
55
56
  this.debouncer.add(payload.conversationId, message, payload.provenance ?? null);
56
57
  },
58
+ onMessageDeleted: (payload) => {
59
+ this.debouncer.removeMessage(payload.conversationId, payload.messageId);
60
+ this.onMessageDeleted?.(payload);
61
+ },
57
62
  onAgentContext: (ctx) => {
58
63
  this.onAgentContext?.(ctx);
59
64
  },
@@ -99,6 +104,9 @@ export class RealtimeManager {
99
104
  setConversationUpdatedHandler(cb) {
100
105
  this.onConversationUpdated = cb;
101
106
  }
107
+ setMessageDeletedHandler(cb) {
108
+ this.onMessageDeleted = cb;
109
+ }
102
110
  setConnectionHandlers(handlers) {
103
111
  this.onConnected = handlers.onConnected ?? null;
104
112
  this.onDisconnected = handlers.onDisconnected ?? null;
@@ -63,6 +63,8 @@ export declare class SessionManager {
63
63
  get sessionCount(): number;
64
64
  /** Number of queued batches waiting behind the active turn for this conversation. */
65
65
  getQueueDepth(conversationId: string): number;
66
+ /** Drop one not-yet-running queued message for a conversation. */
67
+ dropQueuedMessage(conversationId: string, messageId: string): CanonMessage[];
66
68
  /** Drop queued, not-yet-running batches for a conversation. */
67
69
  dropQueued(conversationId: string): CanonMessage[];
68
70
  /** Drop queued work and clear retained context for a conversation. */
@@ -199,6 +199,42 @@ export class SessionManager {
199
199
  getQueueDepth(conversationId) {
200
200
  return this.queues.get(conversationId)?.length ?? 0;
201
201
  }
202
+ /** Drop one not-yet-running queued message for a conversation. */
203
+ dropQueuedMessage(conversationId, messageId) {
204
+ const queue = this.queues.get(conversationId);
205
+ if (!queue || queue.length === 0)
206
+ return [];
207
+ const droppedMessages = [];
208
+ const nextQueue = [];
209
+ for (const item of queue) {
210
+ const keptMessages = item.messages.filter((message) => {
211
+ const drop = message.id === messageId;
212
+ if (drop)
213
+ droppedMessages.push(message);
214
+ return !drop;
215
+ });
216
+ if (keptMessages.length === 0) {
217
+ item.resolve();
218
+ }
219
+ else if (keptMessages.length !== item.messages.length) {
220
+ nextQueue.push({ ...item, messages: keptMessages });
221
+ }
222
+ else {
223
+ nextQueue.push(item);
224
+ }
225
+ }
226
+ if (droppedMessages.length === 0)
227
+ return [];
228
+ if (nextQueue.length === 0) {
229
+ this.queues.delete(conversationId);
230
+ this.pending.delete(conversationId);
231
+ }
232
+ else {
233
+ this.queues.set(conversationId, nextQueue);
234
+ }
235
+ this.removeMessagesFromSession(conversationId, droppedMessages);
236
+ return droppedMessages;
237
+ }
202
238
  /** Drop queued, not-yet-running batches for a conversation. */
203
239
  dropQueued(conversationId) {
204
240
  const queue = this.queues.get(conversationId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/agent-sdk",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
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": "^0.19.0"
31
+ "@canonmsg/core": "^0.19.3"
32
32
  },
33
33
  "publishConfig": {
34
34
  "access": "public"