@canonmsg/agent-sdk 2.1.2 → 2.3.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 +40 -0
- package/dist/canon-agent.d.ts +4 -1
- package/dist/canon-agent.js +19 -0
- package/dist/index.d.ts +2 -2
- package/dist/media.js +7 -0
- package/dist/realtime.d.ts +3 -1
- package/dist/realtime.js +8 -0
- package/dist/types.d.ts +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -176,6 +176,7 @@ The `message` event handler receives a context object with:
|
|
|
176
176
|
| `provenance` | `CanonRuntimeProvenance` | Canon-computed sender/conversation context for the latest inbound message in this batch |
|
|
177
177
|
| `requestApproval` | `(request) => Promise<ApprovalResult>` | Render a Canon approval card, wait for a response, and return the decision to the runtime |
|
|
178
178
|
| `requestRuntimeInput` | `(request) => Promise<RuntimeInputResult>` | Render a Canon input card for clarification, sudo, or secret values |
|
|
179
|
+
| `requestCard` / `sendCard` | functions | Render a generic `canon.card.v1` rich card; action cards can return `{ actionId, values }` |
|
|
179
180
|
| `media` | `{ materialize, uploadFile, replyWithFile }` | Canon-managed access to real media bytes via `~/.canon/media-cache` plus local-file uploads back into Canon |
|
|
180
181
|
| `session` | `SessionInfo \| undefined` | Per-conversation queue/session state when sessions are enabled |
|
|
181
182
|
| `turn` | `TurnController \| undefined` | Live turn-state helpers for thinking/streaming/tool/waiting-input |
|
|
@@ -185,10 +186,47 @@ Messages from the agent itself are automatically filtered out -- your handler on
|
|
|
185
186
|
|
|
186
187
|
`ctx.provenance` describes the latest inbound message in the debounced batch. Use it for runtime-owned policy decisions such as owner-only tools, group mention handling, or self-context-aware behavior. Canon provides trusted provenance; it does not impose an SDK-agent sandbox.
|
|
187
188
|
|
|
189
|
+
## Reaction Updates
|
|
190
|
+
|
|
191
|
+
Agents can use `ctx.react(messageId, emoji)` to toggle any valid emoji reaction on a message. Reactions are also observable through the stream:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
agent.on('messageUpdated', async ({ conversationId, messageId, changes }) => {
|
|
195
|
+
if (changes.reactions) {
|
|
196
|
+
console.log('Reaction state changed', conversationId, messageId, changes.reactions);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Reaction update events are interaction state, not new chat turns. They do not call the `message` handler or wake another agent turn.
|
|
202
|
+
|
|
188
203
|
### Human-in-the-loop cards
|
|
189
204
|
|
|
190
205
|
Use `ctx.requestRuntimeInput(...)` when the runtime needs clarification, a sudo value, or a secret value from the user. Use `ctx.requestApproval(...)` when the runtime needs an allow/deny decision before taking an action. Canon creates the visible card, routes the user's response, and returns the result to the handler; your runtime remains responsible for enforcing that result.
|
|
191
206
|
|
|
207
|
+
Use `ctx.requestCard(...)` for generic rich reports and action forms. A `canon.card.v1` action may include small structured fields; Canon validates the selected action and declared field values, but your runtime still decides what to do with them:
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
const review = await ctx.requestCard({
|
|
211
|
+
card: {
|
|
212
|
+
schema: 'canon.card.v1',
|
|
213
|
+
title: 'Review draft',
|
|
214
|
+
fallbackText: 'Review draft: approve or request changes.',
|
|
215
|
+
blocks: [{
|
|
216
|
+
kind: 'actions',
|
|
217
|
+
actions: [
|
|
218
|
+
{ id: 'approve', label: 'Approve', tone: 'positive' },
|
|
219
|
+
{
|
|
220
|
+
id: 'revise',
|
|
221
|
+
label: 'Request changes',
|
|
222
|
+
fields: [{ id: 'note', label: 'What should change?', type: 'textarea', required: true }],
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
}],
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
192
230
|
## Contact Request Awareness
|
|
193
231
|
|
|
194
232
|
Agents can also observe contact-request lifecycle events without becoming the approver:
|
|
@@ -254,6 +292,8 @@ agent.on('message', async ({ messages, media }) => {
|
|
|
254
292
|
- `media.uploadFile(path, options?)` uploads a local file into the current Canon conversation and returns the canonical attachment metadata.
|
|
255
293
|
- `media.replyWithFile(path, text?, options?)` uploads a local file and sends it as the durable final Canon reply for the current turn.
|
|
256
294
|
|
|
295
|
+
GIFs are regular image attachments. Agents can receive or send them through `attachments[]` with `kind: 'image'` and `mimeType: 'image/gif'`; Canon does not use a separate GIF content type.
|
|
296
|
+
|
|
257
297
|
The public helpers are also available from the Node-only subpath export:
|
|
258
298
|
|
|
259
299
|
```typescript
|
package/dist/canon-agent.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AddMemberResult, type CanonContact, type CanonRuntimeActivityItem, type CanonRuntimeCommandDescriptor, type CanonRuntimeFact, type CanonRuntimePrimitiveId, type ContactCardPayload, type ClearRuntimeActivityOptions, type CreateContactRequestResult } from '@canonmsg/core';
|
|
2
|
-
import type { CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, CreateConversationOptions, MessageHandler, ReachOutOptions, ReachOutResult, ContactRequestHandler, RuntimeSignalHandler, RuntimePrimitiveHandler } from './types.js';
|
|
2
|
+
import type { 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
|
|
5
5
|
* endpoints in CanonClient — the same surface a human user would hit through
|
|
@@ -30,6 +30,7 @@ export declare class CanonAgent {
|
|
|
30
30
|
private contactApprovedHandler;
|
|
31
31
|
private contactAddedHandler;
|
|
32
32
|
private contactRemovedHandler;
|
|
33
|
+
private messageUpdatedHandler;
|
|
33
34
|
private interruptHandler;
|
|
34
35
|
private stopAndDropHandler;
|
|
35
36
|
private newSessionHandler;
|
|
@@ -61,6 +62,7 @@ export declare class CanonAgent {
|
|
|
61
62
|
private ensureApprovalManager;
|
|
62
63
|
private filterApprovalReplyMessages;
|
|
63
64
|
on(event: 'message', handler: MessageHandler): void;
|
|
65
|
+
on(event: 'messageUpdated', handler: MessageUpdatedHandler): void;
|
|
64
66
|
on(event: 'contactRequest', handler: ContactRequestHandler): void;
|
|
65
67
|
on(event: 'contactApproved', handler: ContactRequestHandler): void;
|
|
66
68
|
on(event: 'contactAdded', handler: ContactAddedHandler): void;
|
|
@@ -111,6 +113,7 @@ export declare class CanonAgent {
|
|
|
111
113
|
}>;
|
|
112
114
|
private handleContactRequestEvent;
|
|
113
115
|
private handleContactGraphEvent;
|
|
116
|
+
private handleMessageUpdatedEvent;
|
|
114
117
|
stop(): Promise<void>;
|
|
115
118
|
private hasInterruptSupport;
|
|
116
119
|
private hasStopAndDropSupport;
|
package/dist/canon-agent.js
CHANGED
|
@@ -32,6 +32,7 @@ const DEFAULT_SDK_RUNTIME_DESCRIPTOR = {
|
|
|
32
32
|
result: 'action_or_values',
|
|
33
33
|
maxTimeoutMs: 30 * 60_000,
|
|
34
34
|
blockKinds: ['summary', 'metricGrid', 'chart', 'table', 'list', 'callout', 'actions'],
|
|
35
|
+
actionFieldTypes: ['text', 'textarea', 'select', 'multiSelect', 'boolean'],
|
|
35
36
|
native: true,
|
|
36
37
|
},
|
|
37
38
|
},
|
|
@@ -234,6 +235,7 @@ export class CanonAgent {
|
|
|
234
235
|
contactApprovedHandler = null;
|
|
235
236
|
contactAddedHandler = null;
|
|
236
237
|
contactRemovedHandler = null;
|
|
238
|
+
messageUpdatedHandler = null;
|
|
237
239
|
interruptHandler = null;
|
|
238
240
|
stopAndDropHandler = null;
|
|
239
241
|
newSessionHandler = null;
|
|
@@ -354,6 +356,10 @@ export class CanonAgent {
|
|
|
354
356
|
this.handler = handler;
|
|
355
357
|
return;
|
|
356
358
|
}
|
|
359
|
+
if (event === 'messageUpdated') {
|
|
360
|
+
this.messageUpdatedHandler = handler;
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
357
363
|
if (event === 'contactRequest') {
|
|
358
364
|
this.contactRequestHandler = handler;
|
|
359
365
|
return;
|
|
@@ -576,6 +582,9 @@ export class CanonAgent {
|
|
|
576
582
|
rtm.setConversationUpdatedHandler((payload) => {
|
|
577
583
|
this.handleConversationUpdated(payload);
|
|
578
584
|
});
|
|
585
|
+
rtm.setMessageUpdatedHandler((payload) => {
|
|
586
|
+
void this.handleMessageUpdatedEvent(payload);
|
|
587
|
+
});
|
|
579
588
|
rtm.setMessageDeletedHandler((payload) => {
|
|
580
589
|
this.sessionManager?.dropQueuedMessage(payload.conversationId, payload.messageId);
|
|
581
590
|
});
|
|
@@ -647,6 +656,16 @@ export class CanonAgent {
|
|
|
647
656
|
console.error('[canon-sdk] Contact-graph handler failed:', error instanceof Error ? error.message : error);
|
|
648
657
|
}
|
|
649
658
|
}
|
|
659
|
+
async handleMessageUpdatedEvent(payload) {
|
|
660
|
+
if (!this.messageUpdatedHandler)
|
|
661
|
+
return;
|
|
662
|
+
try {
|
|
663
|
+
await this.messageUpdatedHandler(payload);
|
|
664
|
+
}
|
|
665
|
+
catch (error) {
|
|
666
|
+
console.error('[canon-sdk] Message-updated handler failed:', error instanceof Error ? error.message : error);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
650
669
|
async stop() {
|
|
651
670
|
if (!this.running)
|
|
652
671
|
return;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export { SessionManager } from './session-manager.js';
|
|
|
6
6
|
export { DEFAULT_MEDIA_CACHE_DIR, getCodexImagePath, getMessageAttachments, inferUploadMimeType, isAnthropicImageAttachment, materializeAttachment, materializeMessageMedia, materializeReplyContextMedia, resolveAttachmentMimeType, sendMediaFileMessage, toAnthropicImageBlock, uploadMediaFile, } from './media.js';
|
|
7
7
|
export type { AnthropicImageBlock, AnthropicImageMimeType, MaterializeMediaOptions, MaterializedCanonAttachment, MaterializedCanonReplyContext, ReplyWithFileOptions, UploadMediaFileOptions, } from './media.js';
|
|
8
8
|
export type { SessionConfig, Session } from './session-manager.js';
|
|
9
|
-
export type { AgentContext, CanonGroupContext, CanonKnownRecentParticipant, CanonMembershipChange, CanonContactRequest, CanonMessage, CanonConversation, CanonReplyContext, CanonSelfContext, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, SendMessageOptions, CreateConversationOptions, } from '@canonmsg/core';
|
|
10
|
-
export type { CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, ContactRequestHandler, MessageHandler, MessageHandlerContext, ProgressMessageOptions, ProgressMessageResult, ReachOutOptions, ReachOutResult, RuntimeApprovalRequest, RuntimeInputRequest, RuntimeInputResult, RuntimeControlSurface, RuntimePrimitiveContext, RuntimePrimitiveHandler, RuntimePrimitiveHandlers, SessionInfo, SessionOptions, DeliveryMode, } from './types.js';
|
|
9
|
+
export type { AgentContext, CanonGroupContext, CanonKnownRecentParticipant, CanonMembershipChange, CanonContactRequest, CanonMessage, CanonConversation, CanonReplyContext, CanonSelfContext, MessageUpdatedPayload, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, SendMessageOptions, CreateConversationOptions, } from '@canonmsg/core';
|
|
10
|
+
export type { CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, ContactRequestHandler, MessageHandler, MessageHandlerContext, MessageUpdatedHandler, ProgressMessageOptions, ProgressMessageResult, ReachOutOptions, ReachOutResult, RuntimeApprovalRequest, RuntimeInputRequest, RuntimeInputResult, RuntimeControlSurface, RuntimePrimitiveContext, RuntimePrimitiveHandler, RuntimePrimitiveHandlers, SessionInfo, SessionOptions, DeliveryMode, } from './types.js';
|
package/dist/media.js
CHANGED
|
@@ -17,6 +17,10 @@ const EXTENSION_BY_MIME = {
|
|
|
17
17
|
'audio/ogg': 'ogg',
|
|
18
18
|
'audio/webm': 'webm',
|
|
19
19
|
'audio/wav': 'wav',
|
|
20
|
+
'video/mp4': 'mp4',
|
|
21
|
+
'video/quicktime': 'mov',
|
|
22
|
+
'video/webm': 'webm',
|
|
23
|
+
'video/x-m4v': 'm4v',
|
|
20
24
|
'image/gif': 'gif',
|
|
21
25
|
'image/jpeg': 'jpg',
|
|
22
26
|
'image/png': 'png',
|
|
@@ -36,6 +40,9 @@ const MIME_BY_EXTENSION = {
|
|
|
36
40
|
'.txt': 'text/plain',
|
|
37
41
|
'.wav': 'audio/wav',
|
|
38
42
|
'.webm': 'audio/webm',
|
|
43
|
+
'.m4v': 'video/x-m4v',
|
|
44
|
+
'.mov': 'video/quicktime',
|
|
45
|
+
'.mp4': 'video/mp4',
|
|
39
46
|
'.webp': 'image/webp',
|
|
40
47
|
'.zip': 'application/zip',
|
|
41
48
|
};
|
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 } from '@canonmsg/core';
|
|
1
|
+
import { type AgentContext, type CanonClient, type ContactAddedPayload, type ContactApprovedPayload, type ContactRemovedPayload, type ContactRequestPayload, type ConversationUpdatedPayload, type MessageUpdatedPayload } from '@canonmsg/core';
|
|
2
2
|
import { Debouncer } from './debouncer.js';
|
|
3
3
|
/**
|
|
4
4
|
* Wraps @canonmsg/core's CanonStream with SDK-specific features:
|
|
@@ -19,6 +19,7 @@ export declare class RealtimeManager {
|
|
|
19
19
|
private onContactAdded;
|
|
20
20
|
private onContactRemoved;
|
|
21
21
|
private onConversationUpdated;
|
|
22
|
+
private onMessageUpdated;
|
|
22
23
|
private onMessageDeleted;
|
|
23
24
|
private onConnected;
|
|
24
25
|
private onDisconnected;
|
|
@@ -34,6 +35,7 @@ export declare class RealtimeManager {
|
|
|
34
35
|
onContactRemoved?: (payload: ContactRemovedPayload) => void;
|
|
35
36
|
}): void;
|
|
36
37
|
setConversationUpdatedHandler(cb: (payload: ConversationUpdatedPayload) => void): void;
|
|
38
|
+
setMessageUpdatedHandler(cb: (payload: MessageUpdatedPayload) => void): void;
|
|
37
39
|
setMessageDeletedHandler(cb: (payload: {
|
|
38
40
|
conversationId: string;
|
|
39
41
|
messageId: string;
|
package/dist/realtime.js
CHANGED
|
@@ -18,6 +18,7 @@ export class RealtimeManager {
|
|
|
18
18
|
onContactAdded = null;
|
|
19
19
|
onContactRemoved = null;
|
|
20
20
|
onConversationUpdated = null;
|
|
21
|
+
onMessageUpdated = null;
|
|
21
22
|
onMessageDeleted = null;
|
|
22
23
|
onConnected = null;
|
|
23
24
|
onDisconnected = null;
|
|
@@ -42,6 +43,7 @@ export class RealtimeManager {
|
|
|
42
43
|
text: m.text ?? null,
|
|
43
44
|
attachments: m.attachments ?? [],
|
|
44
45
|
mentions: m.mentions ?? [],
|
|
46
|
+
...(m.reactions ? { reactions: m.reactions } : {}),
|
|
45
47
|
replyTo: m.replyTo ?? null,
|
|
46
48
|
replyToPosition: m.replyToPosition ?? null,
|
|
47
49
|
...(m.forwarded === true || m.forwardedFrom
|
|
@@ -62,6 +64,9 @@ export class RealtimeManager {
|
|
|
62
64
|
this.debouncer.removeMessage(payload.conversationId, payload.messageId);
|
|
63
65
|
this.onMessageDeleted?.(payload);
|
|
64
66
|
},
|
|
67
|
+
onMessageUpdated: (payload) => {
|
|
68
|
+
this.onMessageUpdated?.(payload);
|
|
69
|
+
},
|
|
65
70
|
onAgentContext: (ctx) => {
|
|
66
71
|
this.onAgentContext?.(ctx);
|
|
67
72
|
},
|
|
@@ -123,6 +128,9 @@ export class RealtimeManager {
|
|
|
123
128
|
setConversationUpdatedHandler(cb) {
|
|
124
129
|
this.onConversationUpdated = cb;
|
|
125
130
|
}
|
|
131
|
+
setMessageUpdatedHandler(cb) {
|
|
132
|
+
this.onMessageUpdated = cb;
|
|
133
|
+
}
|
|
126
134
|
setMessageDeletedHandler(cb) {
|
|
127
135
|
this.onMessageDeleted = cb;
|
|
128
136
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -192,6 +192,7 @@ export interface MessageHandlerContext {
|
|
|
192
192
|
abortSignal: AbortSignal;
|
|
193
193
|
}
|
|
194
194
|
export type MessageHandler = (ctx: MessageHandlerContext) => Promise<void>;
|
|
195
|
+
export type MessageUpdatedHandler = (payload: import('@canonmsg/core').MessageUpdatedPayload) => void | Promise<void>;
|
|
195
196
|
export interface SessionOptions {
|
|
196
197
|
/** Enable per-conversation session management (default: false) */
|
|
197
198
|
enabled: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/agent-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.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": "^1.
|
|
31
|
+
"@canonmsg/core": "^1.6.0"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|