@canonmsg/agent-sdk 1.1.1 → 1.1.3
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.js +54 -40
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +19 -14
- package/package.json +2 -2
package/dist/canon-agent.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CanonClient, createRuntimeStatePublisher, FINAL_MESSAGE_HANDOFF_MS, initRTDBAuth, rtdbRead, rtdbWrite,
|
|
1
|
+
import { CanonClient, createRuntimeStatePublisher, FINAL_MESSAGE_HANDOFF_MS, initRTDBAuth, rtdbRead, rtdbWrite, normalizeTurnMetadata, reachOutToCanonContact, } from '@canonmsg/core';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { AuthManager } from './auth.js';
|
|
4
4
|
import { Debouncer } from './debouncer.js';
|
|
@@ -150,9 +150,12 @@ export class CanonAgent {
|
|
|
150
150
|
async reachOut(card, options) {
|
|
151
151
|
const targetUserId = card.userId;
|
|
152
152
|
// Include the opener/request payloads in the dedupe key so two concurrent
|
|
153
|
-
// calls with different `text` or
|
|
153
|
+
// calls with different `text`, `requestMessage`, or setup choices don't silently collapse
|
|
154
154
|
// and lose the second caller's intended side effect.
|
|
155
|
-
const
|
|
155
|
+
const contextualKey = options?.selfContext
|
|
156
|
+
? `${options.sourceConversationId ?? ''}\u0000${options.selfContext.type}\u0000${options.selfContext.context}`
|
|
157
|
+
: '';
|
|
158
|
+
const inFlightKey = `${targetUserId}\u0000${options?.text ?? ''}\u0000${options?.requestMessage ?? ''}\u0000${JSON.stringify(options?.sessionConfig ?? null)}\u0000${contextualKey}`;
|
|
156
159
|
const inFlight = this.reachOutInFlight.get(inFlightKey);
|
|
157
160
|
if (inFlight)
|
|
158
161
|
return inFlight;
|
|
@@ -163,10 +166,34 @@ export class CanonAgent {
|
|
|
163
166
|
return promise;
|
|
164
167
|
}
|
|
165
168
|
async executeReachOut(targetUserId, options) {
|
|
169
|
+
if (options?.selfContext) {
|
|
170
|
+
if (!options.sourceConversationId) {
|
|
171
|
+
throw new Error('sourceConversationId is required for contextual reachOut');
|
|
172
|
+
}
|
|
173
|
+
if (!options.text) {
|
|
174
|
+
throw new Error('text is required for contextual reachOut');
|
|
175
|
+
}
|
|
176
|
+
const result = await this.apiClient.sendContextualMessage({
|
|
177
|
+
sourceConversationId: options.sourceConversationId,
|
|
178
|
+
targetUserId,
|
|
179
|
+
text: options.text,
|
|
180
|
+
selfContext: options.selfContext,
|
|
181
|
+
requestMessage: options.requestMessage ?? null,
|
|
182
|
+
sessionConfig: options.sessionConfig ?? null,
|
|
183
|
+
});
|
|
184
|
+
return result.status === 'messaged'
|
|
185
|
+
? {
|
|
186
|
+
status: 'messaged',
|
|
187
|
+
conversationId: result.conversationId,
|
|
188
|
+
messageId: result.messageId,
|
|
189
|
+
}
|
|
190
|
+
: result;
|
|
191
|
+
}
|
|
166
192
|
return reachOutToCanonContact(this.apiClient, {
|
|
167
193
|
targetUserId,
|
|
168
194
|
text: options?.text ?? null,
|
|
169
195
|
requestMessage: options?.requestMessage ?? null,
|
|
196
|
+
sessionConfig: options?.sessionConfig ?? null,
|
|
170
197
|
});
|
|
171
198
|
}
|
|
172
199
|
async start() {
|
|
@@ -633,6 +660,9 @@ export class CanonAgent {
|
|
|
633
660
|
catch { }
|
|
634
661
|
const result = await this.apiClient.sendMessage(conversationId, text, {
|
|
635
662
|
...(options ?? {}),
|
|
663
|
+
...(options?.selfContextId === undefined && activeSelfContextId
|
|
664
|
+
? { selfContextId: activeSelfContextId }
|
|
665
|
+
: {}),
|
|
636
666
|
metadata: {
|
|
637
667
|
...(options?.metadata ?? {}),
|
|
638
668
|
turnId,
|
|
@@ -671,11 +701,8 @@ export class CanonAgent {
|
|
|
671
701
|
m.isOwner = m.senderId === ownerId;
|
|
672
702
|
}
|
|
673
703
|
}
|
|
674
|
-
const
|
|
675
|
-
|
|
676
|
-
?? null;
|
|
677
|
-
const activeWorkSessions = mergeWorkSessionContexts(explicitWorkSession, page.workSessions ?? []);
|
|
678
|
-
const workSession = explicitWorkSession;
|
|
704
|
+
const selfContexts = page.selfContexts ?? [];
|
|
705
|
+
const activeSelfContextId = selfContexts[0]?.id;
|
|
679
706
|
// Build agent context (fallback to minimal if not yet received)
|
|
680
707
|
const agent = this.agentContext ?? {
|
|
681
708
|
agentId: this.agentId,
|
|
@@ -692,32 +719,21 @@ export class CanonAgent {
|
|
|
692
719
|
const react = (messageId, emoji) => this.apiClient.react(conversationId, messageId, emoji);
|
|
693
720
|
const addMember = (userId) => this.apiClient.addMember(conversationId, userId);
|
|
694
721
|
const removeMember = (userId) => this.apiClient.removeMember(conversationId, userId);
|
|
695
|
-
const
|
|
696
|
-
conversationId,
|
|
697
|
-
...
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
targetConversationId,
|
|
708
|
-
text,
|
|
709
|
-
...(options ?? {}),
|
|
710
|
-
messageOptions: {
|
|
711
|
-
...(options?.messageOptions ?? {}),
|
|
712
|
-
metadata: {
|
|
713
|
-
...(options?.messageOptions?.metadata ?? {}),
|
|
714
|
-
turnId,
|
|
715
|
-
turnSemantics: 'turn_complete',
|
|
716
|
-
turnComplete: true,
|
|
717
|
-
},
|
|
722
|
+
const sendContextualMessage = (target, text, options) => this.apiClient.sendContextualMessage({
|
|
723
|
+
sourceConversationId: conversationId,
|
|
724
|
+
...target,
|
|
725
|
+
text,
|
|
726
|
+
...options,
|
|
727
|
+
messageOptions: {
|
|
728
|
+
...(options.messageOptions ?? {}),
|
|
729
|
+
metadata: {
|
|
730
|
+
...(options.messageOptions?.metadata ?? {}),
|
|
731
|
+
turnId,
|
|
732
|
+
turnSemantics: 'turn_complete',
|
|
733
|
+
turnComplete: true,
|
|
718
734
|
},
|
|
719
|
-
}
|
|
720
|
-
};
|
|
735
|
+
},
|
|
736
|
+
});
|
|
721
737
|
const uploadFile = (filePath, options) => uploadMediaFile(this.apiClient, conversationId, filePath, options);
|
|
722
738
|
const replyWithFile = async (filePath, text = '', options) => {
|
|
723
739
|
try {
|
|
@@ -732,13 +748,15 @@ export class CanonAgent {
|
|
|
732
748
|
? { replyToPosition: options.replyToPosition }
|
|
733
749
|
: {}),
|
|
734
750
|
...(options?.mentions ? { mentions: options.mentions } : {}),
|
|
751
|
+
...(options?.selfContextId === undefined && activeSelfContextId
|
|
752
|
+
? { selfContextId: activeSelfContextId }
|
|
753
|
+
: {}),
|
|
735
754
|
metadata: {
|
|
736
755
|
...(options?.metadata ?? {}),
|
|
737
756
|
turnId,
|
|
738
757
|
turnSemantics: 'turn_complete',
|
|
739
758
|
turnComplete: true,
|
|
740
759
|
},
|
|
741
|
-
...(options?.workSessionId ? { workSessionId: options.workSessionId } : {}),
|
|
742
760
|
contentType: uploaded.attachment.kind,
|
|
743
761
|
attachments: [uploaded.attachment],
|
|
744
762
|
});
|
|
@@ -766,13 +784,9 @@ export class CanonAgent {
|
|
|
766
784
|
react,
|
|
767
785
|
addMember,
|
|
768
786
|
removeMember,
|
|
769
|
-
|
|
770
|
-
getWorkSession,
|
|
771
|
-
updateWorkSessionContext,
|
|
772
|
-
sendLinkedMessage,
|
|
787
|
+
sendContextualMessage,
|
|
773
788
|
agent,
|
|
774
|
-
|
|
775
|
-
activeWorkSessions,
|
|
789
|
+
selfContexts,
|
|
776
790
|
abortSignal: abortController.signal,
|
|
777
791
|
media: {
|
|
778
792
|
materialize: (message = hydratedMessages[hydratedMessages.length - 1], options) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export { SessionManager } from './session-manager.js';
|
|
|
6
6
|
export { getCodexImagePath, getMessageAttachments, inferUploadMimeType, isAnthropicImageAttachment, materializeAttachment, materializeMessageMedia, resolveAttachmentMimeType, toAnthropicImageBlock, uploadMediaFile, } from './media.js';
|
|
7
7
|
export type { AnthropicImageBlock, AnthropicImageMimeType, MaterializeMediaOptions, MaterializedCanonAttachment, ReplyWithFileOptions, UploadMediaFileOptions, } from './media.js';
|
|
8
8
|
export type { SessionConfig, Session } from './session-manager.js';
|
|
9
|
-
export type { AgentContext, CanonContactRequest, CanonMessage, CanonConversation,
|
|
9
|
+
export type { AgentContext, CanonContactRequest, CanonMessage, CanonConversation, CanonSelfContext, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, SendMessageOptions, CreateConversationOptions, } from '@canonmsg/core';
|
|
10
10
|
export type { CanonAgentOptions, ContactAddedHandler, ContactRemovedHandler, ContactRequestHandler, MessageHandler, MessageHandlerContext, ProgressMessageOptions, ProgressMessageResult, ReachOutOptions, ReachOutResult, SessionInfo, SessionOptions, DeliveryMode, } from './types.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { AddMemberResult, AgentClientType, CanonRuntimeDescriptor, CanonMessage, CanonConversation, CanonContact, CanonContactRequest, CanonResolveAdmissionResult, ContactAddedPayload, ContactRemovedPayload, ContactSource, AgentContext, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload,
|
|
2
|
-
import type { AddMemberResult, CanonMessage, CanonConversation, CanonRuntimeActionDispatch,
|
|
1
|
+
export type { AddMemberResult, AgentClientType, CanonRuntimeDescriptor, CanonMessage, CanonConversation, CanonContact, CanonContactRequest, CanonResolveAdmissionResult, ContactAddedPayload, ContactRemovedPayload, ContactSource, AgentContext, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload, CanonSelfContext, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, SendMessageOptions, SessionConfig, CreateConversationOptions, TurnLifecycleState, } from '@canonmsg/core';
|
|
2
|
+
import type { AddMemberResult, CanonMessage, CanonConversation, CanonRuntimeActionDispatch, SendMessageOptions, SendContextualSelfContextInput, SessionConfig } from '@canonmsg/core';
|
|
3
3
|
import type { MaterializeMediaOptions, MaterializedCanonAttachment, ReplyWithFileOptions, UploadMediaFileOptions } from './media.js';
|
|
4
4
|
export interface ProgressMessageOptions extends SendMessageOptions {
|
|
5
5
|
/**
|
|
@@ -61,20 +61,16 @@ export interface MessageHandlerContext {
|
|
|
61
61
|
addMember: (userId: string) => Promise<AddMemberResult>;
|
|
62
62
|
/** Remove a member from this conversation (requires owner/admin role) */
|
|
63
63
|
removeMember: (userId: string) => Promise<void>;
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
/** Send into another conversation under an existing or lazily created Canon work session. */
|
|
71
|
-
sendLinkedMessage: (targetConversationId: string, text: string, options?: Omit<import('@canonmsg/core').SendLinkedMessageOptions, 'sourceConversationId' | 'targetConversationId' | 'text'>) => Promise<import('@canonmsg/core').SendLinkedMessageResult>;
|
|
64
|
+
/** Send into another Canon conversation with private cross-session self-context. */
|
|
65
|
+
sendContextualMessage: (target: {
|
|
66
|
+
targetConversationId: string;
|
|
67
|
+
} | {
|
|
68
|
+
targetUserId: string;
|
|
69
|
+
}, text: string, options: Omit<import('@canonmsg/core').SendContextualMessageOptions, 'sourceConversationId' | 'targetConversationId' | 'targetUserId' | 'text'>) => Promise<import('@canonmsg/core').SendContextualMessageResult>;
|
|
72
70
|
/** Trusted agent identity & access context */
|
|
73
71
|
agent: import('@canonmsg/core').AgentContext;
|
|
74
|
-
/** Canon-provided
|
|
75
|
-
|
|
76
|
-
/** All active Canon work sessions currently linked to this conversation. */
|
|
77
|
-
activeWorkSessions?: import('@canonmsg/core').CanonWorkSessionContext[];
|
|
72
|
+
/** Canon-provided private context explaining this agent's cross-session actions. */
|
|
73
|
+
selfContexts?: import('@canonmsg/core').CanonSelfContext[];
|
|
78
74
|
/** Canon-managed local media access for the current conversation. */
|
|
79
75
|
media: {
|
|
80
76
|
materialize: (message?: CanonMessage, options?: Omit<MaterializeMediaOptions, 'agentId' | 'conversationId' | 'messageId'>) => Promise<MaterializedCanonAttachment[]>;
|
|
@@ -165,6 +161,9 @@ export type ReachOutResult = {
|
|
|
165
161
|
} | {
|
|
166
162
|
status: 'pending';
|
|
167
163
|
requestId: string | null;
|
|
164
|
+
} | {
|
|
165
|
+
status: 'setup_required';
|
|
166
|
+
reason: string;
|
|
168
167
|
} | {
|
|
169
168
|
status: 'blocked' | 'unavailable';
|
|
170
169
|
reason: string;
|
|
@@ -174,4 +173,10 @@ export interface ReachOutOptions {
|
|
|
174
173
|
text?: string;
|
|
175
174
|
/** Optional contact-request note. Defaults to `text` when admission is `request-required`. */
|
|
176
175
|
requestMessage?: string;
|
|
176
|
+
/** Explicit session setup to use when the contact-card target is an agent. */
|
|
177
|
+
sessionConfig?: SessionConfig | null;
|
|
178
|
+
/** Source conversation for contextual cross-session reach-outs. */
|
|
179
|
+
sourceConversationId?: string;
|
|
180
|
+
/** Private context for the agent when this reach-out sends a cross-session message. */
|
|
181
|
+
selfContext?: SendContextualSelfContextInput;
|
|
177
182
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/agent-sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
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.15.
|
|
31
|
+
"@canonmsg/core": "^0.15.5"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|