@canonmsg/core 0.10.0 → 0.11.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/index.d.ts CHANGED
@@ -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
@@ -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,47 @@
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.accessLevel)
43
+ parts.push(`access: ${card.accessLevel}`);
44
+ if (card.about)
45
+ parts.push(`about: ${card.about}`);
46
+ return `[Contact card] "${displayName}" — ${parts.join(' · ')}`;
47
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/core",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Canon core — shared types, REST client, SSE stream, and registration for Canon messaging",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",