@canonmsg/core 0.7.4 → 0.8.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.
@@ -0,0 +1,16 @@
1
+ import type { AgentRuntime, AgentSessionSnapshot, SessionConfig, SessionState } from './types.js';
2
+ import type { TurnState } from './turn-protocol.js';
3
+ import { type CanonWorkSessionContext } from './work-session.js';
4
+ export interface BuildAgentSessionSnapshotInput {
5
+ conversationId: string;
6
+ agentId: string;
7
+ runtime?: AgentRuntime | null;
8
+ sessionConfig?: SessionConfig | null;
9
+ sessionState?: SessionState | null;
10
+ turnState?: TurnState | null;
11
+ workSession?: CanonWorkSessionContext | null;
12
+ workSessions?: CanonWorkSessionContext[] | null;
13
+ lastHeartbeatAt?: number | null;
14
+ updatedAt?: number | null;
15
+ }
16
+ export declare function buildAgentSessionSnapshot(input: BuildAgentSessionSnapshotInput): AgentSessionSnapshot;
@@ -0,0 +1,77 @@
1
+ import { mergeWorkSessionContexts, } from './work-session.js';
2
+ function buildWorkSessionSummary(workSession, workSessions) {
3
+ const merged = mergeWorkSessionContexts(workSession, workSessions);
4
+ const primary = merged[0];
5
+ if (!primary?.id) {
6
+ return null;
7
+ }
8
+ return {
9
+ count: merged.length,
10
+ id: primary.id,
11
+ title: primary.title ?? null,
12
+ objective: primary.objective ?? null,
13
+ status: primary.status ?? null,
14
+ };
15
+ }
16
+ export function buildAgentSessionSnapshot(input) {
17
+ const modelOptions = input.sessionState?.availableModels
18
+ ?? input.sessionConfig?.availableModels
19
+ ?? input.runtime?.availableModels
20
+ ?? [];
21
+ const workspaceOptions = input.sessionConfig?.workspaceOptions
22
+ ?? input.runtime?.availableWorkspaces
23
+ ?? [];
24
+ return {
25
+ conversationId: input.conversationId,
26
+ agentId: input.agentId,
27
+ clientType: input.sessionConfig?.clientType
28
+ ?? input.sessionState?.clientType
29
+ ?? input.runtime?.clientType,
30
+ hostMode: Boolean(input.sessionState?.hostMode
31
+ ?? input.sessionConfig?.hostMode
32
+ ?? input.runtime?.hostMode),
33
+ model: input.sessionState?.model
34
+ ?? input.sessionConfig?.model
35
+ ?? input.runtime?.defaultModel
36
+ ?? modelOptions[0]?.value,
37
+ modelOptions,
38
+ permissionMode: input.sessionState?.permissionMode
39
+ ?? input.sessionConfig?.permissionMode
40
+ ?? input.runtime?.defaultPermissionMode,
41
+ permissionModeOptions: input.runtime?.availablePermissionModes ?? [],
42
+ effort: input.sessionState?.effort ?? input.sessionConfig?.effort,
43
+ runtimeControlValues: input.sessionState?.runtimeControlValues
44
+ ?? input.sessionConfig?.runtimeControlValues,
45
+ workspaceId: input.sessionConfig?.workspaceId
46
+ ?? input.runtime?.defaultWorkspaceId
47
+ ?? workspaceOptions[0]?.id,
48
+ workspaceOptions,
49
+ executionMode: input.sessionState?.executionMode
50
+ ?? input.sessionConfig?.executionMode,
51
+ availableExecutionModes: input.sessionConfig?.availableExecutionModes
52
+ ?? input.runtime?.availableExecutionModes
53
+ ?? [],
54
+ executionBranch: input.sessionState?.executionBranch,
55
+ resolvedWorkspaceLabel: undefined,
56
+ resolvedCwd: input.sessionState?.cwd,
57
+ worktreePath: input.sessionState?.worktreePath,
58
+ executionFallbackReason: input.sessionState?.executionFallbackReason,
59
+ state: input.sessionState?.state,
60
+ turnState: input.turnState?.state,
61
+ supportsQueue: input.turnState?.capabilities?.supportsQueue,
62
+ queueDepth: input.turnState?.queueDepth ?? 0,
63
+ waitingForInput: input.turnState?.state === 'waiting_input'
64
+ || input.sessionState?.state === 'requires_action',
65
+ contextUsage: input.sessionState?.contextUsage,
66
+ lastError: input.sessionState?.lastError,
67
+ lastHeartbeatAt: input.lastHeartbeatAt
68
+ ?? input.runtime?.updatedAt
69
+ ?? input.sessionState?.updatedAt,
70
+ workSession: buildWorkSessionSummary(input.workSession, input.workSessions),
71
+ updatedAt: input.updatedAt
72
+ ?? input.turnState?.updatedAt
73
+ ?? input.sessionState?.updatedAt
74
+ ?? input.sessionConfig?.updatedAt
75
+ ?? input.runtime?.updatedAt,
76
+ };
77
+ }
package/dist/browser.d.ts CHANGED
@@ -1,12 +1,17 @@
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, AgentRuntime, MediaAttachment, MediaAttachmentKind, ModelOption, PermissionModeOption, SessionConfig, WorkspaceOption, } from './types.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, CanonRuntimeExecutionMetadata, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, RuntimeUpdatedPayload, RuntimeInfoPayload, ResolvedAdmission, SessionConfig, TurnUpdatedPayload, WorkspaceOption, } 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';
8
8
  export { buildWorkSessionPromptLines, buildWorkSessionsPromptLines, mergeWorkSessionContexts, } from './work-session.js';
9
+ export { buildAgentSessionSnapshot } from './agent-session.js';
9
10
  export type { AgentBehaviorSettings, ParticipationHistoryMessage, ParticipationHistorySnapshot, ParticipationStyle, ResolvedAgentBehaviorPolicy, } from './policy.js';
10
11
  export { buildParticipationHistorySnapshot, buildParticipationHistorySnapshots, buildBehaviorPolicyLines, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, evaluateParticipationPolicy, getDefaultParticipationPolicy, resolveAgentBehaviorPolicy, } from './policy.js';
11
12
  export { DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, isTurnOpen, normalizeTurnMetadata, normalizeTurnState, resolveTurnMessageSemantics, shouldPromoteConversationMessage, shouldTriggerAgentTurn, } from './turn-protocol.js';
12
13
  export type { DeliveryIntent, InboundDisposition, RuntimeCapabilities, TriggerDecision, TurnLifecycleState, TurnMessageSemantics, TurnMetadata, TurnState, } from './turn-protocol.js';
14
+ export { buildApprovalReply, buildApprovalRequest, buildApprovalOutcome, generateApprovalId, parseTextApprovalReply, redactSecrets, } from './approval-format.js';
15
+ export type { ApprovalRequestMetadata, ApprovalReplyMetadata, SessionRule, ApprovalResult, ApprovalConfig, } from './approval-types.js';
16
+ export { buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, } from './runtime-cards.js';
17
+ export type { ClaudeQuestionMetadata, ClaudeQuestionReplyMetadata, PlanApprovalMetadata, PlanApprovalReplyMetadata, RuntimeQuestionDefinition, RuntimeQuestionOption, } from './runtime-cards.js';
package/dist/browser.js CHANGED
@@ -3,5 +3,8 @@ 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
4
  export { EXECUTION_ENVIRONMENT_MODES, isExecutionEnvironmentMode, } from './execution-environment-mode.js';
5
5
  export { buildWorkSessionPromptLines, buildWorkSessionsPromptLines, mergeWorkSessionContexts, } from './work-session.js';
6
+ export { buildAgentSessionSnapshot } from './agent-session.js';
6
7
  export { buildParticipationHistorySnapshot, buildParticipationHistorySnapshots, buildBehaviorPolicyLines, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, evaluateParticipationPolicy, getDefaultParticipationPolicy, resolveAgentBehaviorPolicy, } from './policy.js';
7
8
  export { DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, isTurnOpen, normalizeTurnMetadata, normalizeTurnState, resolveTurnMessageSemantics, shouldPromoteConversationMessage, shouldTriggerAgentTurn, } from './turn-protocol.js';
9
+ export { buildApprovalReply, buildApprovalRequest, buildApprovalOutcome, generateApprovalId, parseTextApprovalReply, redactSecrets, } from './approval-format.js';
10
+ export { buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, } from './runtime-cards.js';
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type CanonMessage, type CanonConversation, type CanonMessagesPage, type AgentContext, type MediaAttachment, type SendMessageOptions, type CreateConversationOptions, type RegistrationStatus, type SetStreamingOptions } from './types.js';
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';
2
2
  import type { CanonResolvedWorkSession, CreateWorkSessionOptions, SendLinkedMessageOptions, SendLinkedMessageResult, UpdateWorkSessionConversationOptions } from './work-session.js';
3
3
  import type { InboundDisposition } from './turn-protocol.js';
4
4
  /**
@@ -29,6 +29,8 @@ export declare class CanonClient {
29
29
  createConversation(options: CreateConversationOptions): Promise<{
30
30
  conversationId: string;
31
31
  }>;
32
+ createContactRequest(targetUserId: string, message?: string | null): Promise<CreateContactRequestResult>;
33
+ listContactRequests(): Promise<CanonContactRequest[]>;
32
34
  uploadMedia(conversationId: string, data: string, mimeType: string, fileName?: string): Promise<{
33
35
  url: string;
34
36
  attachment: MediaAttachment;
package/dist/client.js CHANGED
@@ -131,6 +131,42 @@ export class CanonClient {
131
131
  throw new CanonApiError(res.status, await res.text());
132
132
  return res.json();
133
133
  }
134
+ async createContactRequest(targetUserId, message) {
135
+ const res = await fetch(`${this.baseUrl}/contacts/request`, {
136
+ method: 'POST',
137
+ headers: this.authHeaders(),
138
+ body: JSON.stringify({
139
+ targetUserId,
140
+ ...(message !== undefined ? { message } : {}),
141
+ }),
142
+ });
143
+ const body = await res.text();
144
+ if (res.status === 200) {
145
+ return { status: 'open', requestId: null };
146
+ }
147
+ if (res.status === 201) {
148
+ const data = parseJsonBody(body);
149
+ return { status: 'created', requestId: data.requestId };
150
+ }
151
+ if (res.status === 409) {
152
+ const data = parseJsonBody(body);
153
+ if (typeof data.requestId === 'string' && data.requestId.length > 0) {
154
+ return { status: 'duplicate', requestId: data.requestId };
155
+ }
156
+ }
157
+ if (!res.ok)
158
+ throw new CanonApiError(res.status, body);
159
+ throw new CanonApiError(res.status, body || 'Unexpected contact-request response');
160
+ }
161
+ async listContactRequests() {
162
+ const res = await fetch(`${this.baseUrl}/contacts/requests`, {
163
+ headers: this.authHeaders(),
164
+ });
165
+ if (!res.ok)
166
+ throw new CanonApiError(res.status, await res.text());
167
+ const data = await res.json();
168
+ return data.requests;
169
+ }
134
170
  async uploadMedia(conversationId, data, mimeType, fileName) {
135
171
  const res = await fetch(`${this.baseUrl}/media/upload`, {
136
172
  method: 'POST',
@@ -273,3 +309,13 @@ export class CanonApiError extends Error {
273
309
  this.status = status;
274
310
  }
275
311
  }
312
+ function parseJsonBody(body) {
313
+ if (!body)
314
+ return {};
315
+ try {
316
+ return JSON.parse(body);
317
+ }
318
+ catch {
319
+ return {};
320
+ }
321
+ }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  export { AGENT_CAPABILITIES, CLAUDE_PERMISSION_MODE_OPTIONS, } from './types.js';
2
- export type { AgentCapabilities, AgentClientType, CanonMessage, CanonConversation, CanonMessagesPage, AgentContext, MediaAttachment, MediaAttachmentKind, MessageCreatedPayload, TypingPayload, PresencePayload, SendMessageOptions, CreateConversationOptions, RegistrationInput, RegistrationResult, RegistrationStatus, StreamingStatus, SetStreamingOptions, SessionControl, SessionState, SessionConfig, AgentRuntime, ModelOption, PermissionModeOption, WorkspaceOption, } 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, CanonRuntimeExecutionMetadata, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, ModelOption, PermissionModeOption, RuntimeInfoPayload, WorkspaceOption, } 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 { CanonClient, CanonApiError } from './client.js';
6
+ export { buildAgentSessionSnapshot } from './agent-session.js';
6
7
  export { CanonStream } from './stream.js';
7
8
  export type { StreamHandler } from './stream.js';
8
9
  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';
@@ -14,6 +15,8 @@ export { ApprovalManager } from './approval-manager.js';
14
15
  export { generateApprovalId, buildApprovalRequest, buildApprovalReply, buildApprovalOutcome, parseTextApprovalReply, redactSecrets, } from './approval-format.js';
15
16
  export { DEFAULT_APPROVAL_CONFIG, } from './approval-types.js';
16
17
  export type { ApprovalRequestMetadata, ApprovalReplyMetadata, SessionRule, ApprovalResult, ApprovalConfig, } from './approval-types.js';
18
+ export { buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, } from './runtime-cards.js';
19
+ export type { ClaudeQuestionMetadata, ClaudeQuestionReplyMetadata, PlanApprovalMetadata, PlanApprovalReplyMetadata, RuntimeQuestionDefinition, RuntimeQuestionOption, } from './runtime-cards.js';
17
20
  export { createStreamingHelper } from './streaming.js';
18
21
  export type { RTDBHandle, RTDBRef, ServerTimestamp, StreamingHelperOptions, StreamingNode } from './streaming.js';
19
22
  export { loadProfiles, isProfileLocked, acquireLock, releaseLock, isProcessAlive, CANON_DIR, AGENTS_PATH, LOCKS_DIR, } from './agent-profiles.js';
@@ -22,7 +25,7 @@ export { resolveCanonAgent, resolveCanonProfile, getActiveProfile } from './agen
22
25
  export type { ResolvedAgent } from './agent-resolver.js';
23
26
  export { buildConfiguredWorkspaceOptions, buildConversationEnvironmentKey, buildConversationWorktreeSpec, buildPublicWorkspaceOptions, buildWorkspaceOptionId, EXECUTION_ENVIRONMENT_MODES, isEnabledFlag, isExecutionEnvironmentMode, normalizeOptionalString, readSessionWorkspaceConfig, resolveConfiguredWorkspaceCwd, ExecutionEnvironmentError, prepareConversationEnvironment, releaseConversationEnvironment, } from './execution-environment.js';
24
27
  export type { ConfiguredWorkspaceOption, ExecutionEnvironmentMode, PreparedExecutionEnvironment, SessionWorkspaceConfig, } from './execution-environment.js';
25
- export { initRTDBAuth, rtdbWrite, rtdbRead, writeSessionState, clearSessionState, writeTurnState, clearTurnState, } from './rtdb-rest.js';
26
- export type { SessionStatePayload, TurnStatePayload } from './rtdb-rest.js';
28
+ export { initRTDBAuth, rtdbWrite, rtdbRead, patchAgentSessionSnapshot, patchRuntimeInfo, writeRuntimeInfo, clearRuntimeInfo, writeSessionState, clearSessionState, writeTurnState, clearTurnState, } from './rtdb-rest.js';
29
+ export type { AgentSessionSnapshotPatch, RuntimeInfoPayloadData, SessionStatePayload, TurnStatePayload, } from './rtdb-rest.js';
27
30
  export { DEFAULT_BASE_URL, DEFAULT_STREAM_URL, DEFAULT_RTDB_URL, FIREBASE_WEB_API_KEY } from './constants.js';
28
31
  export { resolveCanonBaseUrl } from './base-url.js';
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ export { AGENT_CAPABILITIES, CLAUDE_PERMISSION_MODE_OPTIONS, } from './types.js'
3
3
  export { buildWorkSessionPromptLines, buildWorkSessionsPromptLines, mergeWorkSessionContexts, } from './work-session.js';
4
4
  // Client
5
5
  export { CanonClient, CanonApiError } from './client.js';
6
+ export { buildAgentSessionSnapshot } from './agent-session.js';
6
7
  // Stream
7
8
  export { CanonStream } from './stream.js';
8
9
  export { buildParticipationHistorySnapshot, buildParticipationHistorySnapshots, buildBehaviorPolicyLines, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, evaluateParticipationPolicy, getDefaultParticipationPolicy, resolveAgentBehaviorPolicy, } from './policy.js';
@@ -14,6 +15,7 @@ export { registerAndWaitForApproval } from './registration.js';
14
15
  export { ApprovalManager } from './approval-manager.js';
15
16
  export { generateApprovalId, buildApprovalRequest, buildApprovalReply, buildApprovalOutcome, parseTextApprovalReply, redactSecrets, } from './approval-format.js';
16
17
  export { DEFAULT_APPROVAL_CONFIG, } from './approval-types.js';
18
+ export { buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, } from './runtime-cards.js';
17
19
  // Streaming (RTDB helpers)
18
20
  export { createStreamingHelper } from './streaming.js';
19
21
  // Agent profiles (loading, locking, resolution)
@@ -23,7 +25,7 @@ export { resolveCanonAgent, resolveCanonProfile, getActiveProfile } from './agen
23
25
  // Execution environments for host-mode coding sessions
24
26
  export { buildConfiguredWorkspaceOptions, buildConversationEnvironmentKey, buildConversationWorktreeSpec, buildPublicWorkspaceOptions, buildWorkspaceOptionId, EXECUTION_ENVIRONMENT_MODES, isEnabledFlag, isExecutionEnvironmentMode, normalizeOptionalString, readSessionWorkspaceConfig, resolveConfiguredWorkspaceCwd, ExecutionEnvironmentError, prepareConversationEnvironment, releaseConversationEnvironment, } from './execution-environment.js';
25
27
  // RTDB REST helpers (token exchange, session state, generic read/write)
26
- export { initRTDBAuth, rtdbWrite, rtdbRead, writeSessionState, clearSessionState, writeTurnState, clearTurnState, } from './rtdb-rest.js';
28
+ export { initRTDBAuth, rtdbWrite, rtdbRead, patchAgentSessionSnapshot, patchRuntimeInfo, writeRuntimeInfo, clearRuntimeInfo, writeSessionState, clearSessionState, writeTurnState, clearTurnState, } from './rtdb-rest.js';
27
29
  // Constants
28
30
  export { DEFAULT_BASE_URL, DEFAULT_STREAM_URL, DEFAULT_RTDB_URL, FIREBASE_WEB_API_KEY } from './constants.js';
29
31
  // Base URL resolver
@@ -7,14 +7,18 @@
7
7
  */
8
8
  import type { CanonClient } from './client.js';
9
9
  import type { DeliveryIntent, RuntimeCapabilities, TurnLifecycleState } from './turn-protocol.js';
10
+ import type { CanonControlValue, RuntimeInfoPayload } from './types.js';
10
11
  export interface SessionStatePayload {
11
12
  lastError?: string;
12
13
  model?: string;
13
14
  permissionMode?: string;
14
15
  effort?: string;
16
+ runtimeControlValues?: Record<string, CanonControlValue>;
15
17
  cwd?: string;
16
18
  executionMode?: 'worktree' | 'locked';
17
19
  executionBranch?: string;
20
+ worktreePath?: string;
21
+ executionFallbackReason?: string;
18
22
  hostMode?: boolean;
19
23
  clientType?: string;
20
24
  isActive: boolean;
@@ -50,6 +54,62 @@ export interface TurnStatePayload {
50
54
  '.sv': 'timestamp';
51
55
  };
52
56
  }
57
+ export interface AgentSessionSnapshotPatch {
58
+ clientType?: string;
59
+ hostMode?: boolean;
60
+ model?: string | null;
61
+ modelOptions?: Array<{
62
+ value: string;
63
+ label: string;
64
+ }> | null;
65
+ permissionMode?: string | null;
66
+ permissionModeOptions?: Array<{
67
+ value: string;
68
+ label: string;
69
+ }> | null;
70
+ effort?: string | null;
71
+ runtimeControlValues?: Record<string, CanonControlValue> | null;
72
+ workspaceId?: string | null;
73
+ workspaceOptions?: Array<{
74
+ id: string;
75
+ label: string;
76
+ }> | null;
77
+ executionMode?: 'worktree' | 'locked' | null;
78
+ availableExecutionModes?: Array<'worktree' | 'locked'> | null;
79
+ executionBranch?: string | null;
80
+ resolvedCwd?: string | null;
81
+ worktreePath?: string | null;
82
+ executionFallbackReason?: string | null;
83
+ state?: 'idle' | 'running' | 'requires_action' | null;
84
+ turnState?: TurnLifecycleState | null;
85
+ supportsQueue?: boolean | null;
86
+ queueDepth?: number;
87
+ waitingForInput?: boolean;
88
+ contextUsage?: {
89
+ percentage: number;
90
+ totalTokens: number;
91
+ maxTokens: number;
92
+ } | null;
93
+ lastError?: string | null;
94
+ lastHeartbeatAt?: number | {
95
+ '.sv': 'timestamp';
96
+ };
97
+ workSession?: {
98
+ count: number;
99
+ id: string;
100
+ title?: string | null;
101
+ objective?: string | null;
102
+ status?: string | null;
103
+ } | null;
104
+ updatedAt?: {
105
+ '.sv': 'timestamp';
106
+ };
107
+ }
108
+ export interface RuntimeInfoPayloadData extends Omit<RuntimeInfoPayload, 'updatedAt'> {
109
+ updatedAt: {
110
+ '.sv': 'timestamp';
111
+ };
112
+ }
53
113
  interface RTDBAuthOptions {
54
114
  rtdbUrl?: string;
55
115
  firebaseApiKey?: string;
@@ -63,6 +123,10 @@ interface RTDBClientHandle {
63
123
  clearSessionState(conversationId: string, agentId: string): Promise<void>;
64
124
  writeTurnState(conversationId: string, agentId: string, state: Omit<TurnStatePayload, 'updatedAt'>): Promise<void>;
65
125
  clearTurnState(conversationId: string, agentId: string): Promise<void>;
126
+ patchAgentSessionSnapshot(conversationId: string, agentId: string, snapshot: Omit<AgentSessionSnapshotPatch, 'updatedAt'>): Promise<void>;
127
+ writeRuntimeInfo(conversationId: string, agentId: string, payload: Omit<RuntimeInfoPayload, 'updatedAt'>): Promise<void>;
128
+ patchRuntimeInfo(conversationId: string, agentId: string, payload: Partial<Omit<RuntimeInfoPayload, 'updatedAt'>>): Promise<void>;
129
+ clearRuntimeInfo(conversationId: string, agentId: string): Promise<void>;
66
130
  }
67
131
  /**
68
132
  * Initializes the default RTDB helper and returns a scoped client for callers
@@ -84,4 +148,8 @@ export declare function writeSessionState(conversationId: string, agentId: strin
84
148
  export declare function clearSessionState(conversationId: string, agentId: string): Promise<void>;
85
149
  export declare function writeTurnState(conversationId: string, agentId: string, state: Omit<TurnStatePayload, 'updatedAt'>): Promise<void>;
86
150
  export declare function clearTurnState(conversationId: string, agentId: string): Promise<void>;
151
+ export declare function patchAgentSessionSnapshot(conversationId: string, agentId: string, snapshot: Omit<AgentSessionSnapshotPatch, 'updatedAt'>): Promise<void>;
152
+ export declare function writeRuntimeInfo(conversationId: string, agentId: string, payload: Omit<RuntimeInfoPayload, 'updatedAt'>): Promise<void>;
153
+ export declare function patchRuntimeInfo(conversationId: string, agentId: string, payload: Partial<Omit<RuntimeInfoPayload, 'updatedAt'>>): Promise<void>;
154
+ export declare function clearRuntimeInfo(conversationId: string, agentId: string): Promise<void>;
87
155
  export {};
package/dist/rtdb-rest.js CHANGED
@@ -15,6 +15,12 @@ function normalizeRTDBBase(url) {
15
15
  function normalizeRTDBPath(path) {
16
16
  return path.startsWith('/') ? path : `/${path}`;
17
17
  }
18
+ function buildAgentSessionPath(conversationId, agentId) {
19
+ return `/agent-session/${conversationId}/${agentId}`;
20
+ }
21
+ function buildRuntimeInfoPath(conversationId, agentId) {
22
+ return `/runtime-info/${conversationId}/${agentId}`;
23
+ }
18
24
  function createRTDBClientHandle(client, options) {
19
25
  const rtdbBase = normalizeRTDBBase(options?.rtdbUrl || DEFAULT_RTDB_BASE);
20
26
  const firebaseApiKey = options?.firebaseApiKey || DEFAULT_FIREBASE_API_KEY;
@@ -129,6 +135,30 @@ function createRTDBClientHandle(client, options) {
129
135
  ...state,
130
136
  updatedAt: { '.sv': 'timestamp' },
131
137
  });
138
+ await patch(buildAgentSessionPath(conversationId, agentId), {
139
+ ...(state.clientType ? { clientType: state.clientType } : {}),
140
+ ...(typeof state.hostMode === 'boolean' ? { hostMode: state.hostMode } : {}),
141
+ ...(state.model !== undefined ? { model: state.model } : {}),
142
+ ...(state.permissionMode !== undefined ? { permissionMode: state.permissionMode } : {}),
143
+ ...(state.effort !== undefined ? { effort: state.effort } : {}),
144
+ ...(state.runtimeControlValues !== undefined
145
+ ? { runtimeControlValues: state.runtimeControlValues }
146
+ : {}),
147
+ ...(state.availableModels !== undefined ? { modelOptions: state.availableModels } : {}),
148
+ ...(state.cwd !== undefined ? { resolvedCwd: state.cwd } : {}),
149
+ ...(state.executionMode !== undefined ? { executionMode: state.executionMode } : {}),
150
+ ...(state.executionBranch !== undefined ? { executionBranch: state.executionBranch } : {}),
151
+ ...(state.worktreePath !== undefined ? { worktreePath: state.worktreePath } : {}),
152
+ ...(state.executionFallbackReason !== undefined
153
+ ? { executionFallbackReason: state.executionFallbackReason }
154
+ : {}),
155
+ ...(state.state !== undefined ? { state: state.state } : {}),
156
+ waitingForInput: state.state === 'requires_action',
157
+ ...(state.contextUsage !== undefined ? { contextUsage: state.contextUsage } : {}),
158
+ ...(state.lastError !== undefined ? { lastError: state.lastError } : {}),
159
+ lastHeartbeatAt: { '.sv': 'timestamp' },
160
+ updatedAt: { '.sv': 'timestamp' },
161
+ });
132
162
  }
133
163
  async function clearSessionStateImpl(conversationId, agentId) {
134
164
  try {
@@ -136,6 +166,16 @@ function createRTDBClientHandle(client, options) {
136
166
  isActive: false,
137
167
  updatedAt: { '.sv': 'timestamp' },
138
168
  });
169
+ await patch(buildAgentSessionPath(conversationId, agentId), {
170
+ state: 'idle',
171
+ waitingForInput: false,
172
+ lastError: null,
173
+ executionBranch: null,
174
+ contextUsage: null,
175
+ worktreePath: null,
176
+ executionFallbackReason: null,
177
+ updatedAt: { '.sv': 'timestamp' },
178
+ });
139
179
  }
140
180
  catch (error) {
141
181
  console.error('[canon] RTDB clear failed:', error);
@@ -146,6 +186,16 @@ function createRTDBClientHandle(client, options) {
146
186
  ...state,
147
187
  updatedAt: { '.sv': 'timestamp' },
148
188
  });
189
+ await patch(buildAgentSessionPath(conversationId, agentId), {
190
+ turnState: state.state,
191
+ ...(state.capabilities?.supportsQueue !== undefined
192
+ ? { supportsQueue: state.capabilities.supportsQueue }
193
+ : {}),
194
+ queueDepth: state.queueDepth,
195
+ waitingForInput: state.state === 'waiting_input',
196
+ lastHeartbeatAt: { '.sv': 'timestamp' },
197
+ updatedAt: { '.sv': 'timestamp' },
198
+ });
149
199
  }
150
200
  async function clearTurnStateImpl(conversationId, agentId) {
151
201
  try {
@@ -155,11 +205,38 @@ function createRTDBClientHandle(client, options) {
155
205
  updatedAt: { '.sv': 'timestamp' },
156
206
  completedAt: { '.sv': 'timestamp' },
157
207
  });
208
+ await patch(buildAgentSessionPath(conversationId, agentId), {
209
+ turnState: 'idle',
210
+ queueDepth: 0,
211
+ waitingForInput: false,
212
+ updatedAt: { '.sv': 'timestamp' },
213
+ });
158
214
  }
159
215
  catch (error) {
160
216
  console.error('[canon] RTDB turn clear failed:', error);
161
217
  }
162
218
  }
219
+ async function patchAgentSessionSnapshotImpl(conversationId, agentId, snapshot) {
220
+ await patch(buildAgentSessionPath(conversationId, agentId), {
221
+ ...snapshot,
222
+ updatedAt: { '.sv': 'timestamp' },
223
+ });
224
+ }
225
+ async function writeRuntimeInfoImpl(conversationId, agentId, payload) {
226
+ await write(buildRuntimeInfoPath(conversationId, agentId), {
227
+ ...payload,
228
+ updatedAt: { '.sv': 'timestamp' },
229
+ });
230
+ }
231
+ async function patchRuntimeInfoImpl(conversationId, agentId, payload) {
232
+ await patch(buildRuntimeInfoPath(conversationId, agentId), {
233
+ ...payload,
234
+ updatedAt: { '.sv': 'timestamp' },
235
+ });
236
+ }
237
+ async function clearRuntimeInfoImpl(conversationId, agentId) {
238
+ await remove(buildRuntimeInfoPath(conversationId, agentId));
239
+ }
163
240
  return {
164
241
  read,
165
242
  write,
@@ -169,6 +246,10 @@ function createRTDBClientHandle(client, options) {
169
246
  clearSessionState: clearSessionStateImpl,
170
247
  writeTurnState: writeTurnStateImpl,
171
248
  clearTurnState: clearTurnStateImpl,
249
+ patchAgentSessionSnapshot: patchAgentSessionSnapshotImpl,
250
+ writeRuntimeInfo: writeRuntimeInfoImpl,
251
+ patchRuntimeInfo: patchRuntimeInfoImpl,
252
+ clearRuntimeInfo: clearRuntimeInfoImpl,
172
253
  };
173
254
  }
174
255
  /**
@@ -211,3 +292,15 @@ export async function writeTurnState(conversationId, agentId, state) {
211
292
  export async function clearTurnState(conversationId, agentId) {
212
293
  await getDefaultRTDBClient()?.clearTurnState(conversationId, agentId);
213
294
  }
295
+ export async function patchAgentSessionSnapshot(conversationId, agentId, snapshot) {
296
+ await getDefaultRTDBClient()?.patchAgentSessionSnapshot(conversationId, agentId, snapshot);
297
+ }
298
+ export async function writeRuntimeInfo(conversationId, agentId, payload) {
299
+ await getDefaultRTDBClient()?.writeRuntimeInfo(conversationId, agentId, payload);
300
+ }
301
+ export async function patchRuntimeInfo(conversationId, agentId, payload) {
302
+ await getDefaultRTDBClient()?.patchRuntimeInfo(conversationId, agentId, payload);
303
+ }
304
+ export async function clearRuntimeInfo(conversationId, agentId) {
305
+ await getDefaultRTDBClient()?.clearRuntimeInfo(conversationId, agentId);
306
+ }
@@ -0,0 +1,46 @@
1
+ export interface RuntimeQuestionOption {
2
+ label: string;
3
+ description?: string;
4
+ }
5
+ export interface RuntimeQuestionDefinition {
6
+ question: string;
7
+ header?: string;
8
+ options?: RuntimeQuestionOption[];
9
+ multiSelect?: boolean;
10
+ }
11
+ export interface ClaudeQuestionMetadata {
12
+ type: 'claude_question';
13
+ questionId: string;
14
+ questions: RuntimeQuestionDefinition[];
15
+ }
16
+ export interface ClaudeQuestionReplyMetadata {
17
+ type: 'question_reply';
18
+ questionId: string;
19
+ answers: Record<string, string>;
20
+ }
21
+ export interface PlanApprovalMetadata {
22
+ type: 'plan_approval';
23
+ planId: string;
24
+ }
25
+ export interface PlanApprovalReplyMetadata {
26
+ type: 'plan_approval_reply';
27
+ planId: string;
28
+ decision: 'approve' | 'revise';
29
+ feedback?: string;
30
+ }
31
+ export declare function buildQuestionRequest(questionId: string, questions: RuntimeQuestionDefinition[]): {
32
+ text: string;
33
+ metadata: ClaudeQuestionMetadata;
34
+ };
35
+ export declare function buildQuestionReply(questionId: string, answers: Record<string, string>): {
36
+ text: string;
37
+ metadata: ClaudeQuestionReplyMetadata;
38
+ };
39
+ export declare function buildPlanApprovalRequest(planId: string, text?: string): {
40
+ text: string;
41
+ metadata: PlanApprovalMetadata;
42
+ };
43
+ export declare function buildPlanApprovalReply(planId: string, decision: 'approve' | 'revise', feedback?: string): {
44
+ text: string;
45
+ metadata: PlanApprovalReplyMetadata;
46
+ };
@@ -0,0 +1,44 @@
1
+ export function buildQuestionRequest(questionId, questions) {
2
+ const text = questions.length === 1
3
+ ? questions[0]?.question || 'Question'
4
+ : `Please answer ${questions.length} questions.`;
5
+ return {
6
+ text,
7
+ metadata: {
8
+ type: 'claude_question',
9
+ questionId,
10
+ questions,
11
+ },
12
+ };
13
+ }
14
+ export function buildQuestionReply(questionId, answers) {
15
+ const text = Object.values(answers).filter(Boolean).join(', ') || 'Submitted';
16
+ return {
17
+ text,
18
+ metadata: {
19
+ type: 'question_reply',
20
+ questionId,
21
+ answers,
22
+ },
23
+ };
24
+ }
25
+ export function buildPlanApprovalRequest(planId, text = 'Plan ready for review.') {
26
+ return {
27
+ text,
28
+ metadata: {
29
+ type: 'plan_approval',
30
+ planId,
31
+ },
32
+ };
33
+ }
34
+ export function buildPlanApprovalReply(planId, decision, feedback) {
35
+ return {
36
+ text: decision === 'approve' ? 'Plan approved' : 'Requesting changes',
37
+ metadata: {
38
+ type: 'plan_approval_reply',
39
+ planId,
40
+ decision,
41
+ ...(feedback ? { feedback } : {}),
42
+ },
43
+ };
44
+ }
package/dist/stream.d.ts CHANGED
@@ -1,9 +1,13 @@
1
- import type { AgentContext, MessageCreatedPayload, TypingPayload, PresencePayload } from './types.js';
1
+ import type { AgentContext, ContactApprovedPayload, 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
+ onContactRequest?: (payload: ContactRequestPayload) => void;
6
+ onContactApproved?: (payload: ContactApprovedPayload) => void;
5
7
  onTyping?: (data: TypingPayload) => void;
6
8
  onPresence?: (data: PresencePayload) => void;
9
+ onRuntimeUpdated?: (payload: RuntimeUpdatedPayload) => void;
10
+ onTurnUpdated?: (payload: TurnUpdatedPayload) => void;
7
11
  onMessageDeleted?: (payload: {
8
12
  conversationId: string;
9
13
  messageId: string;
@@ -48,6 +52,10 @@ export declare class CanonStream {
48
52
  private handleMessageCreated;
49
53
  private handleTyping;
50
54
  private handlePresence;
55
+ private handleContactRequest;
56
+ private handleContactApproved;
57
+ private handleRuntimeUpdated;
58
+ private handleTurnUpdated;
51
59
  private handleMessageDeleted;
52
60
  private handleConversationUpdated;
53
61
  private scheduleReconnect;
package/dist/stream.js CHANGED
@@ -140,6 +140,14 @@ export class CanonStream {
140
140
  this.reconnectAttempt = 0;
141
141
  this.handleMessageCreated(data);
142
142
  break;
143
+ case 'contact.request':
144
+ this.reconnectAttempt = 0;
145
+ this.handleContactRequest(data);
146
+ break;
147
+ case 'contact.approved':
148
+ this.reconnectAttempt = 0;
149
+ this.handleContactApproved(data);
150
+ break;
143
151
  case 'typing':
144
152
  this.reconnectAttempt = 0;
145
153
  this.handleTyping(data);
@@ -148,6 +156,14 @@ export class CanonStream {
148
156
  this.reconnectAttempt = 0;
149
157
  this.handlePresence(data);
150
158
  break;
159
+ case 'runtime.updated':
160
+ this.reconnectAttempt = 0;
161
+ this.handleRuntimeUpdated(data);
162
+ break;
163
+ case 'turn.updated':
164
+ this.reconnectAttempt = 0;
165
+ this.handleTurnUpdated(data);
166
+ break;
151
167
  case 'message.deleted':
152
168
  this.reconnectAttempt = 0;
153
169
  this.handleMessageDeleted(data);
@@ -161,6 +177,7 @@ export class CanonStream {
161
177
  break;
162
178
  case 'replay.expired':
163
179
  this.reconnectAttempt = 0;
180
+ this.lastEventId = null;
164
181
  this.handler.onError?.(new Error('Replay expired — some messages may have been missed'));
165
182
  break;
166
183
  case 'error':
@@ -210,6 +227,42 @@ export class CanonStream {
210
227
  // Ignore parse errors for non-critical events
211
228
  }
212
229
  }
230
+ handleContactRequest(raw) {
231
+ try {
232
+ const data = JSON.parse(raw);
233
+ this.handler.onContactRequest?.(data);
234
+ }
235
+ catch {
236
+ // Ignore parse errors for non-critical events
237
+ }
238
+ }
239
+ handleContactApproved(raw) {
240
+ try {
241
+ const data = JSON.parse(raw);
242
+ this.handler.onContactApproved?.(data);
243
+ }
244
+ catch {
245
+ // Ignore parse errors for non-critical events
246
+ }
247
+ }
248
+ handleRuntimeUpdated(raw) {
249
+ try {
250
+ const data = JSON.parse(raw);
251
+ this.handler.onRuntimeUpdated?.(data);
252
+ }
253
+ catch {
254
+ // Ignore parse errors for non-critical events
255
+ }
256
+ }
257
+ handleTurnUpdated(raw) {
258
+ try {
259
+ const data = JSON.parse(raw);
260
+ this.handler.onTurnUpdated?.(data);
261
+ }
262
+ catch {
263
+ // Ignore parse errors for non-critical events
264
+ }
265
+ }
213
266
  handleMessageDeleted(raw) {
214
267
  try {
215
268
  const data = JSON.parse(raw);
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { ExecutionEnvironmentMode } from './execution-environment-mode.js';
2
2
  import type { ResolvedAgentBehaviorPolicy } from './policy.js';
3
+ import type { TurnLifecycleState } from './turn-protocol.js';
3
4
  import type { CanonWorkSessionContext } from './work-session.js';
4
5
  export type { ExecutionEnvironmentMode };
5
6
  export type MediaAttachmentKind = 'image' | 'audio' | 'file';
@@ -79,7 +80,39 @@ export interface CanonMessagesPage {
79
80
  behavior?: ResolvedAgentBehaviorPolicy;
80
81
  workSessions?: CanonWorkSessionContext[];
81
82
  }
83
+ export type CanonContactRequestStatus = 'pending' | 'approved' | 'rejected' | 'expired';
84
+ export interface CanonContactRequest {
85
+ id: string;
86
+ requesterId: string;
87
+ requesterName: string;
88
+ requesterAvatarUrl: string | null;
89
+ targetId: string;
90
+ approverId?: string | null;
91
+ message: string | null;
92
+ status: CanonContactRequestStatus;
93
+ createdAt: string | null;
94
+ resolvedAt?: string | null;
95
+ expiresAt?: string | null;
96
+ }
97
+ export type ContactRequestPayload = CanonContactRequest;
98
+ export type ContactApprovedPayload = CanonContactRequest;
99
+ export type CreateContactRequestResult = {
100
+ status: 'open';
101
+ requestId: null;
102
+ } | {
103
+ status: 'created';
104
+ requestId: string;
105
+ } | {
106
+ status: 'duplicate';
107
+ requestId: string;
108
+ };
82
109
  export type AgentClientType = 'claude-code' | 'openclaw' | 'codex' | 'generic';
110
+ export interface ResolvedAdmission {
111
+ accessLevel: 'open' | 'owner-only';
112
+ discoverable: boolean;
113
+ inboundPolicy: 'open' | 'approval-required' | 'private';
114
+ groupJoinPolicy: 'open' | 'approval-required' | 'private';
115
+ }
83
116
  /** Declares what session controls an agent type supports. */
84
117
  export interface AgentCapabilities {
85
118
  supportsModelSwitch: boolean;
@@ -99,11 +132,92 @@ export interface AgentCapabilities {
99
132
  export interface ModelOption {
100
133
  value: string;
101
134
  label: string;
135
+ description?: string;
102
136
  }
103
137
  export interface WorkspaceOption {
104
138
  id: string;
105
139
  label: string;
106
140
  }
141
+ export interface CanonWorkspaceRootMetadata {
142
+ id: string;
143
+ label: string;
144
+ description?: string;
145
+ defaultRelativePath?: string | null;
146
+ }
147
+ export type CanonControlValue = string;
148
+ export type CanonControlAvailability = 'setup' | 'live' | 'setup_and_live';
149
+ export type CanonControlLiveBehavior = 'immediate' | 'next_turn' | 'none';
150
+ export type CanonControlSelectionPolicy = 'inherit' | 'required_explicit';
151
+ export type CanonRuntimeStreamingMode = 'none' | 'status' | 'snapshot' | 'block' | 'delta';
152
+ export type CanonRuntimeSurfaceMode = 'host' | 'channel' | 'limited_channel' | 'operator';
153
+ export type CanonRuntimeInventoryStatus = 'ready' | 'auth_needed' | 'unknown' | 'configured' | 'running' | 'error';
154
+ export type CanonRuntimeStatusTone = 'default' | 'success' | 'warning' | 'danger';
155
+ export interface CanonControlDescriptor {
156
+ id: string;
157
+ label: string;
158
+ options?: ReadonlyArray<ModelOption>;
159
+ defaultValue?: CanonControlValue | null;
160
+ availability: CanonControlAvailability;
161
+ liveBehavior: CanonControlLiveBehavior;
162
+ selectionPolicy: CanonControlSelectionPolicy;
163
+ description?: string;
164
+ }
165
+ export interface CanonRuntimeDescriptor {
166
+ coreControls: ReadonlyArray<CanonControlDescriptor>;
167
+ runtimeControls?: ReadonlyArray<CanonControlDescriptor>;
168
+ /**
169
+ * Optional setup-time local roots advertised by a runtime. These are
170
+ * metadata only for now; existing session config still selects concrete
171
+ * workspace IDs until root-relative directory selection lands.
172
+ */
173
+ workspaceRoots?: ReadonlyArray<CanonWorkspaceRootMetadata>;
174
+ writableRoots?: ReadonlyArray<CanonWorkspaceRootMetadata>;
175
+ supportsInterrupt?: boolean;
176
+ /**
177
+ * Fidelity of live text exposed through Canon's streaming bubble path.
178
+ * `delta` means token/content deltas, `block` means chunked live previews,
179
+ * `snapshot` means completed assistant-message snapshots, and `status`
180
+ * means activity/tool state without live assistant text.
181
+ */
182
+ streamingTextMode?: CanonRuntimeStreamingMode;
183
+ }
184
+ export interface CanonRuntimeExecutionMetadata {
185
+ resolvedWorkspaceLabel?: string | null;
186
+ resolvedCwd?: string | null;
187
+ workspaceRootId?: string | null;
188
+ workspaceRelativePath?: string | null;
189
+ executionMode?: ExecutionEnvironmentMode | null;
190
+ executionBranch?: string | null;
191
+ worktreePath?: string | null;
192
+ fallbackReason?: string | null;
193
+ }
194
+ export interface CanonRuntimeStatusItem {
195
+ id: string;
196
+ label: string;
197
+ value: string;
198
+ tone?: CanonRuntimeStatusTone;
199
+ }
200
+ export interface CanonRuntimeInventoryEntry {
201
+ id: string;
202
+ label: string;
203
+ status?: CanonRuntimeInventoryStatus;
204
+ description?: string;
205
+ }
206
+ export interface CanonRuntimeInventory {
207
+ id: string;
208
+ label: string;
209
+ entries: ReadonlyArray<CanonRuntimeInventoryEntry>;
210
+ }
211
+ export interface RuntimeInfoPayload {
212
+ descriptor: CanonRuntimeDescriptor;
213
+ surfaceMode?: CanonRuntimeSurfaceMode;
214
+ surfaceLabel?: string;
215
+ statusItems?: ReadonlyArray<CanonRuntimeStatusItem>;
216
+ inventories?: ReadonlyArray<CanonRuntimeInventory>;
217
+ execution?: CanonRuntimeExecutionMetadata | null;
218
+ notes?: ReadonlyArray<string>;
219
+ updatedAt?: number;
220
+ }
107
221
  /** Capability map keyed by clientType. Add new agent types here. */
108
222
  export declare const AGENT_CAPABILITIES: Record<AgentClientType, AgentCapabilities>;
109
223
  /** Trusted agent identity & access context, provided by the server */
@@ -156,6 +270,56 @@ export interface PresencePayload {
156
270
  userId: string;
157
271
  online: boolean;
158
272
  }
273
+ export interface RuntimeUpdatedPayload {
274
+ conversationId: string;
275
+ agentId: string;
276
+ runtime: AgentRuntime | null;
277
+ runtimeInfo?: RuntimeInfoPayload | null;
278
+ sessionState: SessionState | null;
279
+ sessionConfig: SessionConfig | null;
280
+ }
281
+ export interface TurnUpdatedPayload {
282
+ conversationId: string;
283
+ agentId: string;
284
+ turn: import('./turn-protocol.js').TurnState | null;
285
+ }
286
+ export type CanonStreamEvent = {
287
+ type: 'agent.context';
288
+ payload: AgentContext;
289
+ } | {
290
+ type: 'message.created';
291
+ payload: MessageCreatedPayload;
292
+ } | {
293
+ type: 'contact.request';
294
+ payload: ContactRequestPayload;
295
+ } | {
296
+ type: 'contact.approved';
297
+ payload: ContactApprovedPayload;
298
+ } | {
299
+ type: 'typing';
300
+ payload: TypingPayload;
301
+ } | {
302
+ type: 'presence';
303
+ payload: PresencePayload;
304
+ } | {
305
+ type: 'runtime.updated';
306
+ payload: RuntimeUpdatedPayload;
307
+ } | {
308
+ type: 'turn.updated';
309
+ payload: TurnUpdatedPayload;
310
+ } | {
311
+ type: 'message.deleted';
312
+ payload: {
313
+ conversationId: string;
314
+ messageId: string;
315
+ };
316
+ } | {
317
+ type: 'conversation.updated';
318
+ payload: {
319
+ conversationId: string;
320
+ changes: Record<string, unknown>;
321
+ };
322
+ };
159
323
  export interface SendMessageOptions {
160
324
  contentType?: 'text' | 'audio' | 'image' | 'file' | 'contact_card';
161
325
  replyTo?: string;
@@ -183,8 +347,9 @@ export interface SetStreamingOptions {
183
347
  /** Written by Canon app to /control/{convoId}/{agentId}/session in RTDB */
184
348
  export interface SessionControl {
185
349
  model?: string;
186
- permissionMode?: 'default' | 'acceptEdits' | 'plan' | 'bypassPermissions' | 'auto';
187
- effort?: 'low' | 'medium' | 'high' | 'max';
350
+ permissionMode?: string;
351
+ effort?: string;
352
+ runtimeControlValues?: Record<string, CanonControlValue>;
188
353
  updatedAt: number;
189
354
  updatedBy: string;
190
355
  }
@@ -194,9 +359,13 @@ export interface SessionState {
194
359
  model?: string;
195
360
  permissionMode?: string;
196
361
  effort?: string;
362
+ runtimeControlValues?: Record<string, CanonControlValue>;
197
363
  cwd?: string;
198
364
  executionMode?: 'worktree' | 'locked';
199
365
  executionBranch?: string;
366
+ worktreePath?: string;
367
+ executionFallbackReason?: string;
368
+ clientType?: AgentClientType;
200
369
  /** True when the agent is running under the host wrapper (host.ts) which can apply control signals */
201
370
  hostMode?: boolean;
202
371
  isActive: boolean;
@@ -214,6 +383,8 @@ export interface SessionConfig {
214
383
  hostMode?: boolean;
215
384
  model?: string;
216
385
  permissionMode?: string;
386
+ effort?: string;
387
+ runtimeControlValues?: Record<string, CanonControlValue>;
217
388
  workspaceId?: string;
218
389
  /**
219
390
  * Explicitly selected execution mode. Sessions created before this field
@@ -252,6 +423,7 @@ export interface AgentRuntime {
252
423
  defaultModel?: string;
253
424
  defaultPermissionMode?: string;
254
425
  availablePermissionModes?: PermissionModeOption[];
426
+ runtimeDescriptor?: CanonRuntimeDescriptor;
255
427
  defaultWorkspaceId?: string;
256
428
  /**
257
429
  * Execution modes the host will accept. The runtime advertises this so the
@@ -268,6 +440,46 @@ export interface AgentRuntime {
268
440
  availableWorkspaces?: WorkspaceOption[];
269
441
  updatedAt?: number;
270
442
  }
443
+ export interface AgentSessionWorkSessionSummary {
444
+ count: number;
445
+ id: string;
446
+ title?: string | null;
447
+ objective?: string | null;
448
+ status?: CanonWorkSessionContext['status'] | null;
449
+ }
450
+ export interface AgentSessionSnapshot {
451
+ conversationId: string;
452
+ agentId: string;
453
+ clientType?: AgentClientType;
454
+ hostMode?: boolean;
455
+ model?: string;
456
+ modelOptions?: ModelOption[];
457
+ permissionMode?: string;
458
+ permissionModeOptions?: PermissionModeOption[];
459
+ effort?: string;
460
+ runtimeControlValues?: Record<string, CanonControlValue>;
461
+ runtimeDescriptor?: CanonRuntimeDescriptor | null;
462
+ runtimeInfo?: RuntimeInfoPayload | null;
463
+ workspaceId?: string;
464
+ workspaceOptions?: WorkspaceOption[];
465
+ executionMode?: ExecutionEnvironmentMode;
466
+ availableExecutionModes?: ExecutionEnvironmentMode[];
467
+ executionBranch?: string;
468
+ resolvedWorkspaceLabel?: string | null;
469
+ resolvedCwd?: string | null;
470
+ worktreePath?: string | null;
471
+ executionFallbackReason?: string | null;
472
+ state?: SessionState['state'];
473
+ turnState?: TurnLifecycleState;
474
+ supportsQueue?: boolean;
475
+ queueDepth: number;
476
+ waitingForInput: boolean;
477
+ contextUsage?: SessionState['contextUsage'];
478
+ lastError?: string;
479
+ lastHeartbeatAt?: number;
480
+ workSession?: AgentSessionWorkSessionSummary | null;
481
+ updatedAt?: number;
482
+ }
271
483
  export interface RegistrationInput {
272
484
  name: string;
273
485
  description: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/core",
3
- "version": "0.7.4",
3
+ "version": "0.8.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",