@canonmsg/core 0.10.0 → 0.12.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/browser.d.ts +1 -1
- package/dist/client.d.ts +8 -2
- package/dist/client.js +69 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -1
- package/dist/message-format.d.ts +13 -0
- package/dist/message-format.js +45 -0
- package/dist/stream.d.ts +5 -1
- package/dist/stream.js +26 -0
- package/dist/turn-protocol.d.ts +18 -0
- package/dist/turn-protocol.js +14 -0
- package/dist/types.d.ts +81 -7
- package/package.json +1 -1
package/dist/browser.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { AGENT_CAPABILITIES, CLAUDE_PERMISSION_MODE_OPTIONS, } from './types.js';
|
|
2
2
|
export { resolveCanonBaseUrl } from './base-url.js';
|
|
3
3
|
export { DEFAULT_BASE_URL, DEFAULT_STREAM_URL, DEFAULT_RTDB_URL, FIREBASE_WEB_API_KEY } from './constants.js';
|
|
4
|
-
export type { AgentCapabilities, AgentClientType, AgentSessionSnapshot, AgentSessionWorkSessionSummary, AgentRuntime, CanonControlAvailability, CanonControlDescriptor, CanonControlLiveBehavior, CanonControlSelectionPolicy, CanonControlValue, CanonContactRequest, CanonContactRequestStatus, ContactApprovedPayload, ContactRequestPayload, CanonStreamEvent, CreateContactRequestResult, MediaAttachment, MediaAttachmentKind, ModelOption, PermissionModeOption, CanonRuntimeDescriptor, CanonRuntimeActionAvailability, CanonRuntimeActionCategory, CanonRuntimeActionDescriptor, CanonRuntimeActionDispatch, CanonRuntimeActionPlacement, CanonRuntimeExecutionMetadata, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, RuntimeUpdatedPayload, RuntimeInfoPayload, ResolvedAdmission, SessionConfig, TurnUpdatedPayload, WorkspaceOption, WorkspaceOptionSource, } from './types.js';
|
|
4
|
+
export type { AddMemberResult, AgentCapabilities, AgentClientType, AgentSessionSnapshot, AgentSessionWorkSessionSummary, AgentRuntime, CanonControlAvailability, CanonControlDescriptor, CanonControlLiveBehavior, CanonControlSelectionPolicy, CanonControlValue, CanonContact, CanonContactRequest, CanonContactRequestStatus, CanonResolveAdmissionResult, ContactAddedPayload, ContactApprovedPayload, ContactRemovedPayload, ContactRequestPayload, ContactSource, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload, CanonStreamEvent, CreateContactRequestResult, MediaAttachment, MediaAttachmentKind, ModelOption, PermissionModeOption, CanonRuntimeDescriptor, CanonRuntimeActionAvailability, CanonRuntimeActionCategory, CanonRuntimeActionDescriptor, CanonRuntimeActionDispatch, CanonRuntimeActionPlacement, CanonRuntimeExecutionMetadata, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, RuntimeUpdatedPayload, RuntimeInfoPayload, ResolvedAdmission, SessionConfig, TurnUpdatedPayload, WorkspaceOption, WorkspaceOptionSource, } from './types.js';
|
|
5
5
|
export { EXECUTION_ENVIRONMENT_MODES, isExecutionEnvironmentMode, } from './execution-environment-mode.js';
|
|
6
6
|
export type { ExecutionEnvironmentMode } from './execution-environment-mode.js';
|
|
7
7
|
export type { CanonResolvedWorkSession, CanonWorkSession, CanonWorkSessionContext, CanonWorkSessionConversationRole, CanonWorkSessionDisclosureMode, CanonWorkSessionParticipant, CanonWorkSessionStatus, CreateWorkSessionOptions, SendLinkedMessageOptions, SendLinkedMessageResult, UpdateWorkSessionConversationOptions, WorkSessionPromptRenderOptions, } from './work-session.js';
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CanonMessage, type CanonConversation, type CanonContactRequest, type CanonMessagesPage, type AgentContext, type CreateContactRequestResult, type MediaAttachment, type SendMessageOptions, type CreateConversationOptions, type RegistrationStatus, type SetStreamingOptions } from './types.js';
|
|
1
|
+
import { type CanonMessage, type CanonConversation, type CanonContact, type CanonContactRequest, type CanonMessagesPage, type CanonResolveAdmissionResult, type AgentContext, type AddMemberResult, type CreateContactRequestResult, type MediaAttachment, type SendMessageOptions, type CreateConversationOptions, type RegistrationStatus, type SetStreamingOptions } from './types.js';
|
|
2
2
|
import type { CanonResolvedWorkSession, CreateWorkSessionOptions, SendLinkedMessageOptions, SendLinkedMessageResult, UpdateWorkSessionConversationOptions } from './work-session.js';
|
|
3
3
|
import type { InboundDisposition } from './turn-protocol.js';
|
|
4
4
|
/**
|
|
@@ -31,6 +31,12 @@ export declare class CanonClient {
|
|
|
31
31
|
}>;
|
|
32
32
|
createContactRequest(targetUserId: string, message?: string | null): Promise<CreateContactRequestResult>;
|
|
33
33
|
listContactRequests(): Promise<CanonContactRequest[]>;
|
|
34
|
+
listContacts(): Promise<CanonContact[]>;
|
|
35
|
+
getContact(contactId: string): Promise<CanonContact | null>;
|
|
36
|
+
deleteContact(contactId: string): Promise<void>;
|
|
37
|
+
blockUser(userId: string): Promise<void>;
|
|
38
|
+
unblockUser(userId: string): Promise<void>;
|
|
39
|
+
resolveAdmission(targetUserId: string): Promise<CanonResolveAdmissionResult>;
|
|
34
40
|
uploadMedia(conversationId: string, data: string, mimeType: string, fileName?: string): Promise<{
|
|
35
41
|
url: string;
|
|
36
42
|
attachment: MediaAttachment;
|
|
@@ -42,7 +48,7 @@ export declare class CanonClient {
|
|
|
42
48
|
leaveConversation(conversationId: string): Promise<void>;
|
|
43
49
|
react(conversationId: string, messageId: string, emoji: string): Promise<void>;
|
|
44
50
|
updateConversationName(conversationId: string, name: string): Promise<void>;
|
|
45
|
-
addMember(conversationId: string, userId: string): Promise<
|
|
51
|
+
addMember(conversationId: string, userId: string): Promise<AddMemberResult>;
|
|
46
52
|
removeMember(conversationId: string, userId: string): Promise<void>;
|
|
47
53
|
setStreaming(options: SetStreamingOptions): Promise<void>;
|
|
48
54
|
clearStreaming(conversationId: string): Promise<void>;
|
package/dist/client.js
CHANGED
|
@@ -142,7 +142,7 @@ export class CanonClient {
|
|
|
142
142
|
});
|
|
143
143
|
const body = await res.text();
|
|
144
144
|
if (res.status === 200) {
|
|
145
|
-
return { status: 'open'
|
|
145
|
+
return { status: 'open' };
|
|
146
146
|
}
|
|
147
147
|
if (res.status === 201) {
|
|
148
148
|
const data = parseJsonBody(body);
|
|
@@ -167,6 +167,61 @@ export class CanonClient {
|
|
|
167
167
|
const data = await res.json();
|
|
168
168
|
return data.requests;
|
|
169
169
|
}
|
|
170
|
+
async listContacts() {
|
|
171
|
+
const res = await fetch(`${this.baseUrl}/contacts`, {
|
|
172
|
+
headers: this.authHeaders(),
|
|
173
|
+
});
|
|
174
|
+
if (!res.ok)
|
|
175
|
+
throw new CanonApiError(res.status, await res.text());
|
|
176
|
+
const data = await res.json();
|
|
177
|
+
return data.contacts;
|
|
178
|
+
}
|
|
179
|
+
async getContact(contactId) {
|
|
180
|
+
const res = await fetch(`${this.baseUrl}/contacts/${contactId}`, {
|
|
181
|
+
headers: this.authHeaders(),
|
|
182
|
+
});
|
|
183
|
+
if (res.status === 404)
|
|
184
|
+
return null;
|
|
185
|
+
if (!res.ok)
|
|
186
|
+
throw new CanonApiError(res.status, await res.text());
|
|
187
|
+
return res.json();
|
|
188
|
+
}
|
|
189
|
+
async deleteContact(contactId) {
|
|
190
|
+
const res = await fetch(`${this.baseUrl}/contacts/${contactId}`, {
|
|
191
|
+
method: 'DELETE',
|
|
192
|
+
headers: this.authHeaders(),
|
|
193
|
+
});
|
|
194
|
+
if (!res.ok)
|
|
195
|
+
throw new CanonApiError(res.status, await res.text());
|
|
196
|
+
}
|
|
197
|
+
async blockUser(userId) {
|
|
198
|
+
const res = await fetch(`${this.baseUrl}/users/block`, {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
headers: this.authHeaders(),
|
|
201
|
+
body: JSON.stringify({ userId }),
|
|
202
|
+
});
|
|
203
|
+
if (!res.ok)
|
|
204
|
+
throw new CanonApiError(res.status, await res.text());
|
|
205
|
+
}
|
|
206
|
+
async unblockUser(userId) {
|
|
207
|
+
const res = await fetch(`${this.baseUrl}/users/unblock`, {
|
|
208
|
+
method: 'POST',
|
|
209
|
+
headers: this.authHeaders(),
|
|
210
|
+
body: JSON.stringify({ userId }),
|
|
211
|
+
});
|
|
212
|
+
if (!res.ok)
|
|
213
|
+
throw new CanonApiError(res.status, await res.text());
|
|
214
|
+
}
|
|
215
|
+
async resolveAdmission(targetUserId) {
|
|
216
|
+
const res = await fetch(`${this.baseUrl}/admission/resolve`, {
|
|
217
|
+
method: 'POST',
|
|
218
|
+
headers: this.authHeaders(),
|
|
219
|
+
body: JSON.stringify({ targetUserId }),
|
|
220
|
+
});
|
|
221
|
+
if (!res.ok)
|
|
222
|
+
throw new CanonApiError(res.status, await res.text());
|
|
223
|
+
return res.json();
|
|
224
|
+
}
|
|
170
225
|
async uploadMedia(conversationId, data, mimeType, fileName) {
|
|
171
226
|
const res = await fetch(`${this.baseUrl}/media/upload`, {
|
|
172
227
|
method: 'POST',
|
|
@@ -243,8 +298,20 @@ export class CanonClient {
|
|
|
243
298
|
headers: this.authHeaders(),
|
|
244
299
|
body: JSON.stringify({ userId }),
|
|
245
300
|
});
|
|
301
|
+
const body = await res.text();
|
|
246
302
|
if (!res.ok)
|
|
247
|
-
throw new CanonApiError(res.status,
|
|
303
|
+
throw new CanonApiError(res.status, body);
|
|
304
|
+
// 202 means the target requires approval — server created a contact
|
|
305
|
+
// request (kind: 'group_invite') routed to the approver. The actual
|
|
306
|
+
// group join happens when that request is approved.
|
|
307
|
+
if (res.status === 202) {
|
|
308
|
+
const data = parseJsonBody(body);
|
|
309
|
+
if (typeof data.requestId === 'string') {
|
|
310
|
+
return { status: 'pending', requestId: data.requestId };
|
|
311
|
+
}
|
|
312
|
+
throw new CanonApiError(202, 'Server returned 202 without a requestId');
|
|
313
|
+
}
|
|
314
|
+
return { status: 'added' };
|
|
248
315
|
}
|
|
249
316
|
async removeMember(conversationId, userId) {
|
|
250
317
|
const res = await fetch(`${this.baseUrl}/conversations/${conversationId}/members/${userId}`, {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { AGENT_CAPABILITIES, CLAUDE_PERMISSION_MODE_OPTIONS, } from './types.js';
|
|
2
|
-
export type { AgentCapabilities, AgentClientType, CanonControlAvailability, CanonControlDescriptor, CanonControlLiveBehavior, CanonControlSelectionPolicy, CanonControlValue, CanonContactRequest, CanonContactRequestStatus, ContactApprovedPayload, ContactRequestPayload, CanonMessage, CanonConversation, CanonMessagesPage, CreateContactRequestResult, AgentContext, CanonStreamEvent, AgentSessionSnapshot, AgentSessionWorkSessionSummary, ResolvedAdmission, MediaAttachment, MediaAttachmentKind, MessageCreatedPayload, TypingPayload, PresencePayload, RuntimeUpdatedPayload, TurnUpdatedPayload, SendMessageOptions, CreateConversationOptions, RegistrationInput, RegistrationResult, RegistrationStatus, StreamingStatus, SetStreamingOptions, SessionControl, SessionState, SessionConfig, AgentRuntime, CanonRuntimeDescriptor, CanonRuntimeActionAvailability, CanonRuntimeActionCategory, CanonRuntimeActionDescriptor, CanonRuntimeActionDispatch, CanonRuntimeActionPlacement, CanonRuntimeExecutionMetadata, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, ModelOption, PermissionModeOption, RuntimeInfoPayload, WorkspaceOption, WorkspaceOptionSource, } from './types.js';
|
|
2
|
+
export type { AddMemberResult, AgentCapabilities, AgentClientType, CanonControlAvailability, CanonControlDescriptor, CanonControlLiveBehavior, CanonControlSelectionPolicy, CanonControlValue, CanonContact, CanonContactRequest, CanonContactRequestStatus, CanonResolveAdmissionResult, ContactAddedPayload, ContactApprovedPayload, ContactCardPayload, ContactRemovedPayload, ContactRequestPayload, ContactSource, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload, CanonMessage, CanonConversation, CanonMessagesPage, CreateContactRequestResult, AgentContext, CanonStreamEvent, AgentSessionSnapshot, AgentSessionWorkSessionSummary, ResolvedAdmission, MediaAttachment, MediaAttachmentKind, MessageCreatedPayload, TypingPayload, PresencePayload, RuntimeUpdatedPayload, TurnUpdatedPayload, SendMessageOptions, CreateConversationOptions, RegistrationInput, RegistrationResult, RegistrationStatus, StreamingStatus, SetStreamingOptions, SessionControl, SessionState, SessionConfig, AgentRuntime, CanonRuntimeDescriptor, CanonRuntimeActionAvailability, CanonRuntimeActionCategory, CanonRuntimeActionDescriptor, CanonRuntimeActionDispatch, CanonRuntimeActionPlacement, CanonRuntimeExecutionMetadata, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, ModelOption, PermissionModeOption, RuntimeInfoPayload, WorkspaceOption, WorkspaceOptionSource, } from './types.js';
|
|
3
3
|
export type { CanonResolvedWorkSession, CanonWorkSession, CanonWorkSessionContext, CanonWorkSessionConversationRole, CreateWorkSessionOptions, CanonWorkSessionDisclosureMode, CanonWorkSessionParticipant, CanonWorkSessionStatus, SendLinkedMessageOptions, SendLinkedMessageResult, UpdateWorkSessionConversationOptions, WorkSessionPromptRenderOptions, } from './work-session.js';
|
|
4
4
|
export { buildWorkSessionPromptLines, buildWorkSessionsPromptLines, mergeWorkSessionContexts, } from './work-session.js';
|
|
5
5
|
export { buildConfiguredWorkspaceOptionsWithRoots, buildPublicWorkspaceRoots, buildWorkspaceRootId, discoverWorkspaceProjects, } from './workspace-discovery.js';
|
|
@@ -10,8 +10,8 @@ export { CanonStream } from './stream.js';
|
|
|
10
10
|
export type { StreamHandler } from './stream.js';
|
|
11
11
|
export type { PolicyRole, ParticipationStyle, RepresentationMode, PermissionLevel, ConversationScope, AgentBehaviorSettings, Participant, Relationship, ContextOverlay, BehaviorProfile, AdmissionPolicy, RuntimeControlPolicy, ActionApprovalPolicy, ParticipationPolicy, WorkSession, ResolvedPolicy, ResolvedTurnEligibility, ResolvedAgentBehaviorPolicy, ParticipationHistoryMessage, ParticipationHistorySnapshot, ParticipationDecisionInput, ParticipationDecision, } from './policy.js';
|
|
12
12
|
export { buildParticipationHistorySnapshot, buildParticipationHistorySnapshots, buildBehaviorPolicyLines, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, evaluateParticipationPolicy, getDefaultParticipationPolicy, resolveAgentBehaviorPolicy, } from './policy.js';
|
|
13
|
-
export { DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, isTurnOpen, normalizeTurnMetadata, normalizeTurnState, resolveTurnMessageSemantics, shouldPromoteConversationMessage, shouldTriggerAgentTurn, } from './turn-protocol.js';
|
|
14
|
-
export type { DeliveryIntent, TurnMessageSemantics, InboundDisposition, TurnLifecycleState, RuntimeCapabilities, TurnState, TurnMetadata, TriggerDecision, } from './turn-protocol.js';
|
|
13
|
+
export { DEFAULT_RUNTIME_CAPABILITIES, HOST_ADMISSION_ACTION_CAPABILITIES, HOST_ADMISSION_ACTIONS_DISABLED, FINAL_MESSAGE_HANDOFF_MS, isTurnOpen, normalizeTurnMetadata, normalizeTurnState, resolveTurnMessageSemantics, shouldPromoteConversationMessage, shouldTriggerAgentTurn, } from './turn-protocol.js';
|
|
14
|
+
export type { DeliveryIntent, TurnMessageSemantics, InboundDisposition, TurnLifecycleState, RuntimeCapabilities, HostAdmissionActionCapabilities, TurnState, TurnMetadata, TriggerDecision, } from './turn-protocol.js';
|
|
15
15
|
export { registerAndWaitForApproval } from './registration.js';
|
|
16
16
|
export { ApprovalManager } from './approval-manager.js';
|
|
17
17
|
export { generateApprovalId, buildApprovalRequest, buildApprovalReply, buildApprovalOutcome, parseTextApprovalReply, redactSecrets, } from './approval-format.js';
|
|
@@ -29,5 +29,6 @@ export { buildConfiguredWorkspaceOptions, buildConversationEnvironmentKey, build
|
|
|
29
29
|
export type { ConfiguredWorkspaceOption, ExecutionEnvironmentMode, PreparedExecutionEnvironment, SessionWorkspaceConfig, } from './execution-environment.js';
|
|
30
30
|
export { initRTDBAuth, rtdbWrite, rtdbRead, patchAgentSessionSnapshot, patchRuntimeInfo, writeRuntimeInfo, clearRuntimeInfo, writeSessionState, clearSessionState, writeTurnState, clearTurnState, } from './rtdb-rest.js';
|
|
31
31
|
export type { AgentSessionSnapshotPatch, RuntimeInfoPayloadData, SessionStatePayload, TurnStatePayload, } from './rtdb-rest.js';
|
|
32
|
+
export { formatCanonMessageAsText } from './message-format.js';
|
|
32
33
|
export { DEFAULT_BASE_URL, DEFAULT_STREAM_URL, DEFAULT_RTDB_URL, FIREBASE_WEB_API_KEY } from './constants.js';
|
|
33
34
|
export { resolveCanonBaseUrl } from './base-url.js';
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export { buildAgentSessionSnapshot } from './agent-session.js';
|
|
|
9
9
|
export { CanonStream } from './stream.js';
|
|
10
10
|
export { buildParticipationHistorySnapshot, buildParticipationHistorySnapshots, buildBehaviorPolicyLines, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, evaluateParticipationPolicy, getDefaultParticipationPolicy, resolveAgentBehaviorPolicy, } from './policy.js';
|
|
11
11
|
// Turn protocol
|
|
12
|
-
export { DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, isTurnOpen, normalizeTurnMetadata, normalizeTurnState, resolveTurnMessageSemantics, shouldPromoteConversationMessage, shouldTriggerAgentTurn, } from './turn-protocol.js';
|
|
12
|
+
export { DEFAULT_RUNTIME_CAPABILITIES, HOST_ADMISSION_ACTION_CAPABILITIES, HOST_ADMISSION_ACTIONS_DISABLED, FINAL_MESSAGE_HANDOFF_MS, isTurnOpen, normalizeTurnMetadata, normalizeTurnState, resolveTurnMessageSemantics, shouldPromoteConversationMessage, shouldTriggerAgentTurn, } from './turn-protocol.js';
|
|
13
13
|
// Registration
|
|
14
14
|
export { registerAndWaitForApproval } from './registration.js';
|
|
15
15
|
// Approval
|
|
@@ -27,6 +27,8 @@ export { resolveCanonAgent, resolveCanonProfile, getActiveProfile } from './agen
|
|
|
27
27
|
export { buildConfiguredWorkspaceOptions, buildConversationEnvironmentKey, buildConversationWorktreeSpec, buildPublicWorkspaceOptions, buildWorkspaceOptionId, EXECUTION_ENVIRONMENT_MODES, isEnabledFlag, isExecutionEnvironmentMode, normalizeOptionalString, readSessionWorkspaceConfig, resolveConfiguredWorkspaceCwd, ExecutionEnvironmentError, prepareConversationEnvironment, releaseConversationEnvironment, } from './execution-environment.js';
|
|
28
28
|
// RTDB REST helpers (token exchange, session state, generic read/write)
|
|
29
29
|
export { initRTDBAuth, rtdbWrite, rtdbRead, patchAgentSessionSnapshot, patchRuntimeInfo, writeRuntimeInfo, clearRuntimeInfo, writeSessionState, clearSessionState, writeTurnState, clearTurnState, } from './rtdb-rest.js';
|
|
30
|
+
// Message formatting (LLM-facing text projection)
|
|
31
|
+
export { formatCanonMessageAsText } from './message-format.js';
|
|
30
32
|
// Constants
|
|
31
33
|
export { DEFAULT_BASE_URL, DEFAULT_STREAM_URL, DEFAULT_RTDB_URL, FIREBASE_WEB_API_KEY } from './constants.js';
|
|
32
34
|
// Base URL resolver
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CanonMessage } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Project a CanonMessage to a single text representation suitable as a
|
|
4
|
+
* baseline for plugins that feed messages to an LLM as plain text.
|
|
5
|
+
*
|
|
6
|
+
* Plugins that compose richer prompts (placeholders, capability hints,
|
|
7
|
+
* native vision input) layer on top of this — the goal here is only to
|
|
8
|
+
* guarantee that no contentType is ever silently dropped to an empty
|
|
9
|
+
* string. Adding a new contentType to CanonMessage and forgetting to
|
|
10
|
+
* handle it here surfaces in this file's tests, not as a silent
|
|
11
|
+
* regression in every consumer plugin.
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatCanonMessageAsText(message: Pick<CanonMessage, 'contentType' | 'text' | 'attachments' | 'contactCard'>): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project a CanonMessage to a single text representation suitable as a
|
|
3
|
+
* baseline for plugins that feed messages to an LLM as plain text.
|
|
4
|
+
*
|
|
5
|
+
* Plugins that compose richer prompts (placeholders, capability hints,
|
|
6
|
+
* native vision input) layer on top of this — the goal here is only to
|
|
7
|
+
* guarantee that no contentType is ever silently dropped to an empty
|
|
8
|
+
* string. Adding a new contentType to CanonMessage and forgetting to
|
|
9
|
+
* handle it here surfaces in this file's tests, not as a silent
|
|
10
|
+
* regression in every consumer plugin.
|
|
11
|
+
*/
|
|
12
|
+
export function formatCanonMessageAsText(message) {
|
|
13
|
+
if (message.contentType === 'contact_card' && message.contactCard) {
|
|
14
|
+
return formatContactCard(message.contactCard);
|
|
15
|
+
}
|
|
16
|
+
const attachment = pickPrimaryAttachment(message.attachments);
|
|
17
|
+
const trimmedText = typeof message.text === 'string' ? message.text.trim() : '';
|
|
18
|
+
if (attachment?.kind === 'image') {
|
|
19
|
+
return trimmedText ? `[image] ${trimmedText}` : '[image]';
|
|
20
|
+
}
|
|
21
|
+
if (attachment?.kind === 'audio') {
|
|
22
|
+
const seconds = typeof attachment.durationMs === 'number'
|
|
23
|
+
? ` ${Math.round(attachment.durationMs / 1000)}s`
|
|
24
|
+
: '';
|
|
25
|
+
return trimmedText ? `[audio${seconds}] ${trimmedText}` : `[audio${seconds}]`;
|
|
26
|
+
}
|
|
27
|
+
if (attachment?.kind === 'file') {
|
|
28
|
+
const label = attachment.fileName?.trim() || 'file';
|
|
29
|
+
return trimmedText ? `[${label}] ${trimmedText}` : `[${label}]`;
|
|
30
|
+
}
|
|
31
|
+
return trimmedText || '[message]';
|
|
32
|
+
}
|
|
33
|
+
function pickPrimaryAttachment(attachments) {
|
|
34
|
+
const first = attachments?.[0];
|
|
35
|
+
return first?.url ? first : null;
|
|
36
|
+
}
|
|
37
|
+
function formatContactCard(card) {
|
|
38
|
+
const displayName = card.displayName?.trim() || 'Unknown';
|
|
39
|
+
const parts = [card.userType, `userId: ${card.userId}`];
|
|
40
|
+
if (card.ownerName)
|
|
41
|
+
parts.push(`owner: ${card.ownerName}`);
|
|
42
|
+
if (card.about)
|
|
43
|
+
parts.push(`about: ${card.about}`);
|
|
44
|
+
return `[Contact card] "${displayName}" — ${parts.join(' · ')}`;
|
|
45
|
+
}
|
package/dist/stream.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import type { AgentContext, ContactApprovedPayload, ContactRequestPayload, MessageCreatedPayload, TypingPayload, PresencePayload, RuntimeUpdatedPayload, TurnUpdatedPayload } from './types.js';
|
|
1
|
+
import type { AgentContext, ContactAddedPayload, ContactApprovedPayload, ContactRemovedPayload, ContactRequestPayload, MessageCreatedPayload, TypingPayload, PresencePayload, RuntimeUpdatedPayload, TurnUpdatedPayload } from './types.js';
|
|
2
2
|
export type StreamHandler = {
|
|
3
3
|
onMessage: (payload: MessageCreatedPayload) => void;
|
|
4
4
|
onAgentContext?: (ctx: AgentContext) => void;
|
|
5
5
|
onContactRequest?: (payload: ContactRequestPayload) => void;
|
|
6
6
|
onContactApproved?: (payload: ContactApprovedPayload) => void;
|
|
7
|
+
onContactAdded?: (payload: ContactAddedPayload) => void;
|
|
8
|
+
onContactRemoved?: (payload: ContactRemovedPayload) => void;
|
|
7
9
|
onTyping?: (data: TypingPayload) => void;
|
|
8
10
|
onPresence?: (data: PresencePayload) => void;
|
|
9
11
|
onRuntimeUpdated?: (payload: RuntimeUpdatedPayload) => void;
|
|
@@ -54,6 +56,8 @@ export declare class CanonStream {
|
|
|
54
56
|
private handlePresence;
|
|
55
57
|
private handleContactRequest;
|
|
56
58
|
private handleContactApproved;
|
|
59
|
+
private handleContactAdded;
|
|
60
|
+
private handleContactRemoved;
|
|
57
61
|
private handleRuntimeUpdated;
|
|
58
62
|
private handleTurnUpdated;
|
|
59
63
|
private handleMessageDeleted;
|
package/dist/stream.js
CHANGED
|
@@ -148,6 +148,14 @@ export class CanonStream {
|
|
|
148
148
|
this.reconnectAttempt = 0;
|
|
149
149
|
this.handleContactApproved(data);
|
|
150
150
|
break;
|
|
151
|
+
case 'contact.added':
|
|
152
|
+
this.reconnectAttempt = 0;
|
|
153
|
+
this.handleContactAdded(data);
|
|
154
|
+
break;
|
|
155
|
+
case 'contact.removed':
|
|
156
|
+
this.reconnectAttempt = 0;
|
|
157
|
+
this.handleContactRemoved(data);
|
|
158
|
+
break;
|
|
151
159
|
case 'typing':
|
|
152
160
|
this.reconnectAttempt = 0;
|
|
153
161
|
this.handleTyping(data);
|
|
@@ -245,6 +253,24 @@ export class CanonStream {
|
|
|
245
253
|
// Ignore parse errors for non-critical events
|
|
246
254
|
}
|
|
247
255
|
}
|
|
256
|
+
handleContactAdded(raw) {
|
|
257
|
+
try {
|
|
258
|
+
const data = JSON.parse(raw);
|
|
259
|
+
this.handler.onContactAdded?.(data);
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// Ignore parse errors for non-critical events
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
handleContactRemoved(raw) {
|
|
266
|
+
try {
|
|
267
|
+
const data = JSON.parse(raw);
|
|
268
|
+
this.handler.onContactRemoved?.(data);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
// Ignore parse errors for non-critical events
|
|
272
|
+
}
|
|
273
|
+
}
|
|
248
274
|
handleRuntimeUpdated(raw) {
|
|
249
275
|
try {
|
|
250
276
|
const data = JSON.parse(raw);
|
package/dist/turn-protocol.d.ts
CHANGED
|
@@ -36,6 +36,24 @@ export interface TriggerDecision {
|
|
|
36
36
|
reason: string;
|
|
37
37
|
}
|
|
38
38
|
export declare const DEFAULT_RUNTIME_CAPABILITIES: RuntimeCapabilities;
|
|
39
|
+
/**
|
|
40
|
+
* Contact-graph and admission actions a Canon host runtime exposes through the
|
|
41
|
+
* agent SDK. Plugins consult this to decide which tools to register on the
|
|
42
|
+
* LLM's behalf — e.g., whether to advertise a `block_user` tool. A flag is
|
|
43
|
+
* `true` only when the runtime has both the SDK wrapper *and* a tool surface
|
|
44
|
+
* wired up that calls it. Until plugin tool wiring ships, runtimes should
|
|
45
|
+
* advertise `HOST_ADMISSION_ACTIONS_DISABLED` so consumers don't render UI
|
|
46
|
+
* for actions the runtime can't actually perform.
|
|
47
|
+
*/
|
|
48
|
+
export interface HostAdmissionActionCapabilities {
|
|
49
|
+
blockUser: boolean;
|
|
50
|
+
unblockUser: boolean;
|
|
51
|
+
removeContact: boolean;
|
|
52
|
+
requestContact: boolean;
|
|
53
|
+
reachOut: boolean;
|
|
54
|
+
}
|
|
55
|
+
export declare const HOST_ADMISSION_ACTION_CAPABILITIES: HostAdmissionActionCapabilities;
|
|
56
|
+
export declare const HOST_ADMISSION_ACTIONS_DISABLED: HostAdmissionActionCapabilities;
|
|
39
57
|
export declare function normalizeTurnMetadata(metadata: unknown): TurnMetadata | null;
|
|
40
58
|
export declare function normalizeTurnState(value: unknown): TurnState | null;
|
|
41
59
|
export declare function isTurnOpen(turnState: Pick<TurnState, 'state'> | null | undefined): boolean;
|
package/dist/turn-protocol.js
CHANGED
|
@@ -26,6 +26,20 @@ export const DEFAULT_RUNTIME_CAPABILITIES = {
|
|
|
26
26
|
supportsRequiresAction: false,
|
|
27
27
|
supportsNonFinalPermanentMessages: false,
|
|
28
28
|
};
|
|
29
|
+
export const HOST_ADMISSION_ACTION_CAPABILITIES = {
|
|
30
|
+
blockUser: true,
|
|
31
|
+
unblockUser: true,
|
|
32
|
+
removeContact: true,
|
|
33
|
+
requestContact: true,
|
|
34
|
+
reachOut: true,
|
|
35
|
+
};
|
|
36
|
+
export const HOST_ADMISSION_ACTIONS_DISABLED = {
|
|
37
|
+
blockUser: false,
|
|
38
|
+
unblockUser: false,
|
|
39
|
+
removeContact: false,
|
|
40
|
+
requestContact: false,
|
|
41
|
+
reachOut: false,
|
|
42
|
+
};
|
|
29
43
|
function isRecord(value) {
|
|
30
44
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
31
45
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -34,7 +34,6 @@ export interface ContactCardPayload {
|
|
|
34
34
|
isActive?: boolean;
|
|
35
35
|
ownerId?: string;
|
|
36
36
|
ownerName?: string;
|
|
37
|
-
accessLevel?: 'open' | 'owner-only';
|
|
38
37
|
lifecycleState?: string;
|
|
39
38
|
}
|
|
40
39
|
export interface CanonMessage {
|
|
@@ -87,18 +86,40 @@ export interface CanonContactRequest {
|
|
|
87
86
|
requesterName: string;
|
|
88
87
|
requesterAvatarUrl: string | null;
|
|
89
88
|
targetId: string;
|
|
90
|
-
approverId
|
|
89
|
+
approverId: string;
|
|
91
90
|
message: string | null;
|
|
92
91
|
status: CanonContactRequestStatus;
|
|
92
|
+
/** 'dm' for one-to-one contact request, 'group_invite' for stranger-add. */
|
|
93
|
+
kind: 'dm' | 'group_invite';
|
|
94
|
+
groupContext?: {
|
|
95
|
+
conversationId: string;
|
|
96
|
+
groupName: string | null;
|
|
97
|
+
};
|
|
93
98
|
createdAt: string | null;
|
|
94
99
|
resolvedAt?: string | null;
|
|
95
100
|
expiresAt?: string | null;
|
|
96
101
|
}
|
|
97
102
|
export type ContactRequestPayload = CanonContactRequest;
|
|
98
103
|
export type ContactApprovedPayload = CanonContactRequest;
|
|
104
|
+
/**
|
|
105
|
+
* Outcome of `CanonClient.addMember` / `agent.addMember`. The REST endpoint
|
|
106
|
+
* returns 201 on immediate add and 202 on approval-required group invite.
|
|
107
|
+
* Both are success from the protocol's perspective — distinct outcomes for
|
|
108
|
+
* the caller.
|
|
109
|
+
*/
|
|
110
|
+
export type AddMemberResult = {
|
|
111
|
+
status: 'added';
|
|
112
|
+
} | {
|
|
113
|
+
status: 'pending';
|
|
114
|
+
requestId: string;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Successful outcomes of `createContactRequest`. Errors (denied,
|
|
118
|
+
* malformed input) come back as Firebase `HttpsError`s and are not
|
|
119
|
+
* represented here.
|
|
120
|
+
*/
|
|
99
121
|
export type CreateContactRequestResult = {
|
|
100
122
|
status: 'open';
|
|
101
|
-
requestId: null;
|
|
102
123
|
} | {
|
|
103
124
|
status: 'created';
|
|
104
125
|
requestId: string;
|
|
@@ -106,12 +127,50 @@ export type CreateContactRequestResult = {
|
|
|
106
127
|
status: 'duplicate';
|
|
107
128
|
requestId: string;
|
|
108
129
|
};
|
|
130
|
+
export type ContactSource = 'direct_add' | 'phone_book' | 'contact_request' | 'link' | 'qr' | 'group' | 'open_inbound_message'
|
|
131
|
+
/** Sentinel value emitted by stream-service when a doc lacks a source field. */
|
|
132
|
+
| 'unknown';
|
|
133
|
+
/** A single entry from the agent's `users/{agentId}/contacts/` subcollection. */
|
|
134
|
+
export interface CanonContact {
|
|
135
|
+
/** The contact's userId. */
|
|
136
|
+
id: string;
|
|
137
|
+
source: ContactSource;
|
|
138
|
+
addedAt: string | null;
|
|
139
|
+
displayNameOverride: string | null;
|
|
140
|
+
}
|
|
141
|
+
export type ContactAddedPayload = CanonContact;
|
|
142
|
+
export type ContactRemovedPayload = {
|
|
143
|
+
id: string;
|
|
144
|
+
};
|
|
145
|
+
export type ResolvedAdmissionState = 'self' | 'not-found' | 'allowed' | 'request-required' | 'pending-outbound' | 'blocked' | 'inactive' | 'owner-only';
|
|
146
|
+
export interface ResolvedAdmissionTargetSummary {
|
|
147
|
+
id: string;
|
|
148
|
+
displayName?: string;
|
|
149
|
+
avatarUrl?: string | null;
|
|
150
|
+
about?: string;
|
|
151
|
+
userType?: 'human' | 'ai_agent';
|
|
152
|
+
discoverable?: boolean;
|
|
153
|
+
inboundPolicy?: 'open' | 'approval-required' | 'owner-only';
|
|
154
|
+
groupJoinPolicy?: 'open' | 'approval-required' | 'owner-only';
|
|
155
|
+
}
|
|
156
|
+
export interface ResolvedTargetAdmissionPayload {
|
|
157
|
+
state: ResolvedAdmissionState;
|
|
158
|
+
canMessage: boolean;
|
|
159
|
+
canRequestContact: boolean;
|
|
160
|
+
isContact: boolean;
|
|
161
|
+
pendingRequestId?: string;
|
|
162
|
+
blockedByViewer?: boolean;
|
|
163
|
+
blockedByTarget?: boolean;
|
|
164
|
+
}
|
|
165
|
+
export interface CanonResolveAdmissionResult {
|
|
166
|
+
target: ResolvedAdmissionTargetSummary | null;
|
|
167
|
+
admission: ResolvedTargetAdmissionPayload;
|
|
168
|
+
}
|
|
109
169
|
export type AgentClientType = 'claude-code' | 'openclaw' | 'codex' | 'generic';
|
|
110
170
|
export interface ResolvedAdmission {
|
|
111
|
-
accessLevel: 'open' | 'owner-only';
|
|
112
171
|
discoverable: boolean;
|
|
113
|
-
inboundPolicy: 'open' | 'approval-required' | '
|
|
114
|
-
groupJoinPolicy: 'open' | 'approval-required' | '
|
|
172
|
+
inboundPolicy: 'open' | 'approval-required' | 'owner-only';
|
|
173
|
+
groupJoinPolicy: 'open' | 'approval-required' | 'owner-only';
|
|
115
174
|
}
|
|
116
175
|
/** Declares what session controls an agent type supports. */
|
|
117
176
|
export interface AgentCapabilities {
|
|
@@ -219,6 +278,13 @@ export interface CanonRuntimeDescriptor {
|
|
|
219
278
|
* means activity/tool state without live assistant text.
|
|
220
279
|
*/
|
|
221
280
|
streamingTextMode?: CanonRuntimeStreamingMode;
|
|
281
|
+
/**
|
|
282
|
+
* Contact-graph and admission actions this runtime exposes through the
|
|
283
|
+
* agent SDK. Plugins set this to advertise which tools they will surface
|
|
284
|
+
* to the LLM (e.g., block-user, request-contact). When omitted, no
|
|
285
|
+
* admission actions are advertised.
|
|
286
|
+
*/
|
|
287
|
+
admissionActions?: import('./turn-protocol.js').HostAdmissionActionCapabilities;
|
|
222
288
|
}
|
|
223
289
|
export interface CanonRuntimeExecutionMetadata {
|
|
224
290
|
resolvedWorkspaceLabel?: string | null;
|
|
@@ -267,7 +333,9 @@ export interface AgentContext {
|
|
|
267
333
|
description?: string | null;
|
|
268
334
|
ownerId: string;
|
|
269
335
|
ownerName: string;
|
|
270
|
-
|
|
336
|
+
discoverable: boolean;
|
|
337
|
+
inboundPolicy: 'open' | 'approval-required' | 'owner-only';
|
|
338
|
+
groupJoinPolicy: 'open' | 'approval-required' | 'owner-only';
|
|
271
339
|
/** Identifies the agent's client platform for UI feature detection */
|
|
272
340
|
clientType?: AgentClientType;
|
|
273
341
|
defaultBehavior?: ResolvedAgentBehaviorPolicy;
|
|
@@ -334,6 +402,12 @@ export type CanonStreamEvent = {
|
|
|
334
402
|
} | {
|
|
335
403
|
type: 'contact.approved';
|
|
336
404
|
payload: ContactApprovedPayload;
|
|
405
|
+
} | {
|
|
406
|
+
type: 'contact.added';
|
|
407
|
+
payload: ContactAddedPayload;
|
|
408
|
+
} | {
|
|
409
|
+
type: 'contact.removed';
|
|
410
|
+
payload: ContactRemovedPayload;
|
|
337
411
|
} | {
|
|
338
412
|
type: 'typing';
|
|
339
413
|
payload: TypingPayload;
|