@canonmsg/core 0.19.0 → 0.19.2

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.
@@ -1,3 +1,4 @@
1
+ import { redactAgentSessionSnapshotForConversation } from './runtime-presentation.js';
1
2
  function listDescriptorControls(runtime) {
2
3
  const descriptor = runtime?.runtimeDescriptor;
3
4
  return [
@@ -104,7 +105,7 @@ export function buildAgentSessionSnapshot(input) {
104
105
  const executionMode = input.sessionState?.executionMode
105
106
  ?? input.sessionConfig?.executionMode;
106
107
  const controlState = buildControlState(input);
107
- return {
108
+ const snapshot = {
108
109
  conversationId: input.conversationId,
109
110
  agentId: input.agentId,
110
111
  clientType: input.sessionConfig?.clientType
@@ -146,4 +147,5 @@ export function buildAgentSessionSnapshot(input) {
146
147
  ?? input.sessionConfig?.updatedAt
147
148
  ?? input.runtime?.updatedAt,
148
149
  };
150
+ return redactAgentSessionSnapshotForConversation(input.runtime?.runtimeDescriptor, snapshot);
149
151
  }
package/dist/browser.d.ts CHANGED
@@ -1,7 +1,8 @@
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 { AddMemberResult, AgentCapabilities, AgentClientType, AgentSessionSnapshot, 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, CanonRuntimeCommandArgumentChoice, CanonRuntimeCommandArgumentDescriptor, CanonRuntimeCommandArgumentKind, CanonRuntimeCommandDescriptor, CanonRuntimeDetailTier, CanonRuntimeExecutionMetadata, CanonRuntimeProvenance, CanonRuntimeActivityItem, CanonRuntimeActivityKind, CanonRuntimeActivityStatus, CanonRuntimeFact, CanonRuntimeFactGroup, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimePrimitiveId, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, RuntimeUpdatedPayload, RuntimeInfoPayload, RuntimeControlError, RuntimeControlState, RuntimeControlValueSource, ResolvedAdmission, SessionConfig, TurnUpdatedPayload, WorkspaceOption, WorkspaceOptionSource, } from './types.js';
4
+ export type { AddMemberResult, AgentCapabilities, AgentClientType, AgentSessionSnapshot, 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, CanonRuntimeCommandArgumentChoice, CanonRuntimeCommandArgumentDescriptor, CanonRuntimeCommandArgumentKind, CanonRuntimeCommandDescriptor, CanonRuntimeDetailTier, CanonRuntimeExecutionMetadata, CanonRuntimePresentationField, CanonRuntimePresentationHint, CanonRuntimePresentationPolicy, CanonRuntimePresentationPreset, CanonRuntimeVisibility, CanonRuntimeProvenance, CanonRuntimeActivityItem, CanonRuntimeActivityKind, CanonRuntimeActivityStatus, CanonRuntimeFact, CanonRuntimeFactGroup, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimePrimitiveId, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, RuntimeUpdatedPayload, RuntimeInfoPayload, RuntimeControlError, RuntimeControlState, RuntimeControlValueSource, ResolvedAdmission, SessionConfig, TurnUpdatedPayload, WorkspaceOption, WorkspaceOptionSource, } from './types.js';
5
+ export { DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, RUNTIME_PRESENTATION_FIELDS, buildRuntimePresentationPolicy, getRuntimePresentationHint, isRuntimePresentationField, isRuntimePresentationFieldHidden, redactAgentSessionSnapshotForConversation, redactExecutionMetadataForConversation, redactRuntimeDescriptorForConversation, redactRuntimeInfoForConversation, } from './runtime-presentation.js';
5
6
  export { buildRuntimeProvenance, resolveRuntimeProvenance, } from './provenance.js';
6
7
  export { EXECUTION_ENVIRONMENT_MODES, isExecutionEnvironmentMode, } from './execution-environment-mode.js';
7
8
  export type { ExecutionEnvironmentMode } from './execution-environment-mode.js';
@@ -16,5 +17,5 @@ export type { DeliveryIntent, InboundDisposition, RuntimeCapabilities, TriggerDe
16
17
  export { buildApprovalReply, buildApprovalRequest, buildApprovalOutcome, generateApprovalId, parseTextApprovalReply, redactSecrets, } from './approval-format.js';
17
18
  export type { ApprovalRequestCategory, ApprovalRequestDetail, ApprovalRequestMetadata, ApprovalNativeRequestMetadata, ApprovalRisk, ApprovalReplyMetadata, ApprovalOutcomeMetadata, SessionRule, ApprovalResult, ApprovalConfig, } from './approval-types.js';
18
19
  export { DEFAULT_APPROVAL_CONFIG, parseApprovalRequestMetadata, parseApprovalReplyMetadata, parseSessionRule, } from './approval-types.js';
19
- export { buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, } from './runtime-cards.js';
20
- export type { ClaudeQuestionMetadata, ClaudeQuestionReplyMetadata, PlanApprovalMetadata, PlanApprovalReplyMetadata, RuntimeQuestionDefinition, RuntimeQuestionOption, } from './runtime-cards.js';
20
+ export { buildRuntimeInputOutcome, buildRuntimeInputReply, buildRuntimeInputRequest, buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, parseRuntimeInputOutcomeMetadata, parseRuntimeInputReplyMetadata, parseRuntimeInputRequestMetadata, } from './runtime-cards.js';
21
+ export type { ClaudeQuestionMetadata, ClaudeQuestionReplyMetadata, PlanApprovalMetadata, PlanApprovalReplyMetadata, RuntimeInputChoice, RuntimeInputKind, RuntimeInputNativeMetadata, RuntimeInputOutcomeMetadata, RuntimeInputReplyMetadata, RuntimeInputReplyStatus, RuntimeInputRequestMetadata, RuntimeInputResolutionStatus, RuntimeQuestionDefinition, RuntimeQuestionOption, } from './runtime-cards.js';
package/dist/browser.js CHANGED
@@ -1,6 +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 { DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, RUNTIME_PRESENTATION_FIELDS, buildRuntimePresentationPolicy, getRuntimePresentationHint, isRuntimePresentationField, isRuntimePresentationFieldHidden, redactAgentSessionSnapshotForConversation, redactExecutionMetadataForConversation, redactRuntimeDescriptorForConversation, redactRuntimeInfoForConversation, } from './runtime-presentation.js';
4
5
  export { buildRuntimeProvenance, resolveRuntimeProvenance, } from './provenance.js';
5
6
  export { EXECUTION_ENVIRONMENT_MODES, isExecutionEnvironmentMode, } from './execution-environment-mode.js';
6
7
  export { buildSelfContextPromptLines, normalizeSelfContexts, } from './self-context.js';
@@ -10,4 +11,4 @@ export { buildParticipationHistorySnapshot, buildParticipationHistorySnapshots,
10
11
  export { DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, isTurnOpen, normalizeTurnMetadata, normalizeTurnState, resolveTurnMessageSemantics, shouldPromoteConversationMessage, shouldTriggerAgentTurn, } from './turn-protocol.js';
11
12
  export { buildApprovalReply, buildApprovalRequest, buildApprovalOutcome, generateApprovalId, parseTextApprovalReply, redactSecrets, } from './approval-format.js';
12
13
  export { DEFAULT_APPROVAL_CONFIG, parseApprovalRequestMetadata, parseApprovalReplyMetadata, parseSessionRule, } from './approval-types.js';
13
- export { buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, } from './runtime-cards.js';
14
+ export { buildRuntimeInputOutcome, buildRuntimeInputReply, buildRuntimeInputRequest, buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, parseRuntimeInputOutcomeMetadata, parseRuntimeInputReplyMetadata, parseRuntimeInputRequestMetadata, } from './runtime-cards.js';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { AGENT_CAPABILITIES, CLAUDE_PERMISSION_MODE_OPTIONS, } from './types.js';
2
- export type { AddMemberResult, AgentCapabilities, AgentClientType, CanonControlAvailability, CanonControlDescriptor, CanonControlLiveBehavior, CanonControlSelectionPolicy, CanonControlValue, CanonContact, CanonContactRequest, CanonContactRequestStatus, CanonGroupContext, CanonGroupContextMode, CanonKnownRecentParticipant, CanonMembershipChange, CanonResolveAdmissionResult, ConversationUpdatedPayload, ContactAddedPayload, ContactApprovedPayload, ContactCardPayload, ContactRemovedPayload, ContactRequestPayload, ContactSource, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload, CanonMessage, CanonRuntimeProvenance, CanonConversation, CanonMessagesPage, CreateContactRequestResult, AgentContext, CanonStreamEvent, AgentSessionSnapshot, 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, CanonRuntimeCommandArgumentChoice, CanonRuntimeCommandArgumentDescriptor, CanonRuntimeCommandArgumentKind, CanonRuntimeCommandDescriptor, CanonRuntimeDetailTier, CanonRuntimeExecutionMetadata, CanonRuntimeActivityItem, CanonRuntimeActivityKind, CanonRuntimeActivityStatus, CanonRuntimeFact, CanonRuntimeFactGroup, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimePrimitiveId, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, ModelOption, PermissionModeOption, RuntimeInfoPayload, RuntimeControlError, RuntimeControlState, RuntimeControlValueSource, WorkspaceOption, WorkspaceOptionSource, } from './types.js';
2
+ export type { AddMemberResult, AgentCapabilities, AgentClientType, CanonControlAvailability, CanonControlDescriptor, CanonControlLiveBehavior, CanonControlSelectionPolicy, CanonControlValue, CanonContact, CanonContactRequest, CanonContactRequestStatus, CanonGroupContext, CanonGroupContextMode, CanonKnownRecentParticipant, CanonMembershipChange, CanonResolveAdmissionResult, ConversationUpdatedPayload, ContactAddedPayload, ContactApprovedPayload, ContactCardPayload, ContactRemovedPayload, ContactRequestPayload, ContactSource, ResolvedAdmissionState, ResolvedAdmissionTargetSummary, ResolvedTargetAdmissionPayload, CanonMessage, CanonRuntimeProvenance, CanonConversation, CanonMessagesPage, CreateContactRequestResult, AgentContext, CanonStreamEvent, AgentSessionSnapshot, 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, CanonRuntimeCommandArgumentChoice, CanonRuntimeCommandArgumentDescriptor, CanonRuntimeCommandArgumentKind, CanonRuntimeCommandDescriptor, CanonRuntimeDetailTier, CanonRuntimeExecutionMetadata, CanonRuntimePresentationField, CanonRuntimePresentationHint, CanonRuntimePresentationPolicy, CanonRuntimePresentationPreset, CanonRuntimeVisibility, CanonRuntimeActivityItem, CanonRuntimeActivityKind, CanonRuntimeActivityStatus, CanonRuntimeFact, CanonRuntimeFactGroup, CanonRuntimeInventory, CanonRuntimeInventoryEntry, CanonRuntimePrimitiveId, CanonRuntimeStreamingMode, CanonRuntimeStatusItem, CanonRuntimeSurfaceMode, CanonWorkspaceRootMetadata, ModelOption, PermissionModeOption, RuntimeInfoPayload, RuntimeControlError, RuntimeControlState, RuntimeControlValueSource, WorkspaceOption, WorkspaceOptionSource, } from './types.js';
3
+ export { DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, RUNTIME_PRESENTATION_FIELDS, buildRuntimePresentationPolicy, getRuntimePresentationHint, isRuntimePresentationField, isRuntimePresentationFieldHidden, redactAgentRuntimeForConversation, redactAgentSessionSnapshotForConversation, redactExecutionMetadataForConversation, redactRuntimeActivityItemForConversation, redactRuntimeDescriptorForConversation, redactRuntimeInfoForConversation, redactSessionStateForConversation, } from './runtime-presentation.js';
3
4
  export { buildRuntimeProvenance, resolveRuntimeProvenance, } from './provenance.js';
4
5
  export type { CanonSelfContext, CanonSelfContextType, SelfContextPromptRenderOptions, SendContextualMessageOptions, SendContextualMessageResult, SendContextualSelfContextInput, } from './self-context.js';
5
6
  export { buildSelfContextPromptLines, normalizeSelfContexts, resolveMessageActiveSelfContextId, selectActiveSelfContexts, } from './self-context.js';
@@ -19,8 +20,8 @@ export { ApprovalManager } from './approval-manager.js';
19
20
  export { generateApprovalId, buildApprovalRequest, buildApprovalReply, buildApprovalOutcome, parseTextApprovalReply, redactSecrets, } from './approval-format.js';
20
21
  export { DEFAULT_APPROVAL_CONFIG, parseApprovalRequestMetadata, parseApprovalReplyMetadata, parseSessionRule, } from './approval-types.js';
21
22
  export type { ApprovalRequestCategory, ApprovalRequestDetail, ApprovalRequestMetadata, ApprovalNativeRequestMetadata, ApprovalRisk, ApprovalReplyMetadata, ApprovalOutcomeMetadata, SessionRule, ApprovalResult, ApprovalConfig, } from './approval-types.js';
22
- export { buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, } from './runtime-cards.js';
23
- export type { ClaudeQuestionMetadata, ClaudeQuestionReplyMetadata, PlanApprovalMetadata, PlanApprovalReplyMetadata, RuntimeQuestionDefinition, RuntimeQuestionOption, } from './runtime-cards.js';
23
+ export { buildRuntimeInputOutcome, buildRuntimeInputReply, buildRuntimeInputRequest, buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, parseRuntimeInputOutcomeMetadata, parseRuntimeInputReplyMetadata, parseRuntimeInputRequestMetadata, } from './runtime-cards.js';
24
+ export type { ClaudeQuestionMetadata, ClaudeQuestionReplyMetadata, PlanApprovalMetadata, PlanApprovalReplyMetadata, RuntimeInputChoice, RuntimeInputKind, RuntimeInputNativeMetadata, RuntimeInputOutcomeMetadata, RuntimeInputReplyMetadata, RuntimeInputReplyStatus, RuntimeInputRequestMetadata, RuntimeInputResolutionStatus, RuntimeQuestionDefinition, RuntimeQuestionOption, } from './runtime-cards.js';
24
25
  export { createStreamingHelper } from './streaming.js';
25
26
  export type { RTDBHandle, RTDBRef, ServerTimestamp, StreamingHelperOptions, StreamingNode } from './streaming.js';
26
27
  export { clearPendingRegistration, getOrCreatePendingRegistration, loadPendingRegistrations, loadProfiles, savePendingRegistrations, saveProfiles, updatePendingRegistration, upsertAgentProfile, isProfileLocked, acquireLock, releaseLock, isProcessAlive, CANON_DIR, AGENTS_PATH, LOCKS_DIR, } from './agent-profiles.js';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // Types
2
2
  export { AGENT_CAPABILITIES, CLAUDE_PERMISSION_MODE_OPTIONS, } from './types.js';
3
+ export { DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, RUNTIME_PRESENTATION_FIELDS, buildRuntimePresentationPolicy, getRuntimePresentationHint, isRuntimePresentationField, isRuntimePresentationFieldHidden, redactAgentRuntimeForConversation, redactAgentSessionSnapshotForConversation, redactExecutionMetadataForConversation, redactRuntimeActivityItemForConversation, redactRuntimeDescriptorForConversation, redactRuntimeInfoForConversation, redactSessionStateForConversation, } from './runtime-presentation.js';
3
4
  export { buildRuntimeProvenance, resolveRuntimeProvenance, } from './provenance.js';
4
5
  export { buildSelfContextPromptLines, normalizeSelfContexts, resolveMessageActiveSelfContextId, selectActiveSelfContexts, } from './self-context.js';
5
6
  export { buildConfiguredWorkspaceOptionsWithRoots, buildPublicWorkspaceRoots, buildWorkspaceRootId, discoverWorkspaceProjects, } from './workspace-discovery.js';
@@ -18,7 +19,7 @@ export { ackRegistrationApproval, registerAndWaitForApproval, submitRegistration
18
19
  export { ApprovalManager } from './approval-manager.js';
19
20
  export { generateApprovalId, buildApprovalRequest, buildApprovalReply, buildApprovalOutcome, parseTextApprovalReply, redactSecrets, } from './approval-format.js';
20
21
  export { DEFAULT_APPROVAL_CONFIG, parseApprovalRequestMetadata, parseApprovalReplyMetadata, parseSessionRule, } from './approval-types.js';
21
- export { buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, } from './runtime-cards.js';
22
+ export { buildRuntimeInputOutcome, buildRuntimeInputReply, buildRuntimeInputRequest, buildPlanApprovalReply, buildPlanApprovalRequest, buildQuestionReply, buildQuestionRequest, parseRuntimeInputOutcomeMetadata, parseRuntimeInputReplyMetadata, parseRuntimeInputRequestMetadata, } from './runtime-cards.js';
22
23
  // Streaming (RTDB helpers)
23
24
  export { createStreamingHelper } from './streaming.js';
24
25
  // Agent profiles (loading, locking, resolution)
@@ -10,6 +10,7 @@ export interface LocalRuntimeSessionState {
10
10
  codexPolicyFingerprint?: string;
11
11
  threadId?: string;
12
12
  claudeSessionId?: string;
13
+ hermesSessionId?: string;
13
14
  lastInboundMessageId?: string;
14
15
  updatedAt: string;
15
16
  }
@@ -35,6 +35,49 @@ export interface PlanApprovalReplyMetadata {
35
35
  decision: 'approve' | 'revise';
36
36
  feedback?: string;
37
37
  }
38
+ export type RuntimeInputKind = 'clarify' | 'sudo' | 'secret';
39
+ export type RuntimeInputReplyStatus = 'submitted' | 'cancelled';
40
+ export type RuntimeInputResolutionStatus = RuntimeInputReplyStatus | 'timeout';
41
+ export interface RuntimeInputChoice {
42
+ label: string;
43
+ value?: string;
44
+ description?: string;
45
+ }
46
+ export interface RuntimeInputNativeMetadata {
47
+ runtime?: string;
48
+ method?: string;
49
+ requestId?: string;
50
+ sessionKey?: string;
51
+ turnId?: string;
52
+ handles?: Record<string, string>;
53
+ }
54
+ export interface RuntimeInputRequestMetadata {
55
+ type: 'runtime_input_request';
56
+ inputId: string;
57
+ kind: RuntimeInputKind;
58
+ prompt: string;
59
+ title?: string;
60
+ choices?: RuntimeInputChoice[];
61
+ secretName?: string;
62
+ native?: RuntimeInputNativeMetadata;
63
+ expiresAt: string;
64
+ sensitive?: boolean;
65
+ }
66
+ export interface RuntimeInputReplyMetadata {
67
+ type: 'runtime_input_reply';
68
+ inputId: string;
69
+ kind?: RuntimeInputKind;
70
+ status: RuntimeInputReplyStatus;
71
+ answerSummary?: string;
72
+ sensitive?: boolean;
73
+ }
74
+ export interface RuntimeInputOutcomeMetadata {
75
+ type: 'runtime_input_outcome';
76
+ inputId: string;
77
+ kind?: RuntimeInputKind;
78
+ status: RuntimeInputResolutionStatus;
79
+ reason?: 'submitted' | 'cancelled' | 'timeout' | 'expired' | 'interrupted';
80
+ }
38
81
  export declare function buildQuestionRequest(questionId: string, questions: RuntimeQuestionDefinition[]): {
39
82
  text: string;
40
83
  metadata: ClaudeQuestionMetadata;
@@ -51,3 +94,25 @@ export declare function buildPlanApprovalReply(planId: string, decision: 'approv
51
94
  text: string;
52
95
  metadata: PlanApprovalReplyMetadata;
53
96
  };
97
+ export declare function buildRuntimeInputRequest(inputId: string, input: Omit<RuntimeInputRequestMetadata, 'type' | 'inputId'>): {
98
+ text: string;
99
+ metadata: RuntimeInputRequestMetadata;
100
+ };
101
+ export declare function buildRuntimeInputReply(inputId: string, status: RuntimeInputReplyStatus, details?: {
102
+ kind?: RuntimeInputKind;
103
+ answerSummary?: string;
104
+ sensitive?: boolean;
105
+ }): {
106
+ text: string;
107
+ metadata: RuntimeInputReplyMetadata;
108
+ };
109
+ export declare function buildRuntimeInputOutcome(inputId: string, status: RuntimeInputResolutionStatus, details?: {
110
+ kind?: RuntimeInputKind;
111
+ reason?: RuntimeInputOutcomeMetadata['reason'];
112
+ }): {
113
+ text: string;
114
+ metadata: RuntimeInputOutcomeMetadata;
115
+ };
116
+ export declare function parseRuntimeInputRequestMetadata(value: unknown): RuntimeInputRequestMetadata | null;
117
+ export declare function parseRuntimeInputReplyMetadata(value: unknown): RuntimeInputReplyMetadata | null;
118
+ export declare function parseRuntimeInputOutcomeMetadata(value: unknown): RuntimeInputOutcomeMetadata | null;
@@ -1,3 +1,73 @@
1
+ function isRecord(value) {
2
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
3
+ }
4
+ function normalizeString(value, maxLength) {
5
+ if (typeof value !== 'string')
6
+ return null;
7
+ const trimmed = value.trim();
8
+ if (!trimmed || trimmed.length > maxLength)
9
+ return null;
10
+ return trimmed;
11
+ }
12
+ function normalizeRuntimeInputKind(value) {
13
+ return value === 'clarify' || value === 'sudo' || value === 'secret' ? value : null;
14
+ }
15
+ function normalizeRuntimeInputReplyStatus(value) {
16
+ return value === 'submitted' || value === 'cancelled' ? value : null;
17
+ }
18
+ function normalizeRuntimeInputResolutionStatus(value) {
19
+ return value === 'submitted' || value === 'cancelled' || value === 'timeout' ? value : null;
20
+ }
21
+ function normalizeRuntimeInputChoices(value) {
22
+ if (!Array.isArray(value))
23
+ return undefined;
24
+ const choices = value.slice(0, 12).flatMap((entry) => {
25
+ if (!isRecord(entry))
26
+ return [];
27
+ const label = normalizeString(entry.label, 120);
28
+ if (!label)
29
+ return [];
30
+ const choice = { label };
31
+ const choiceValue = normalizeString(entry.value, 200);
32
+ const description = normalizeString(entry.description, 300);
33
+ if (choiceValue)
34
+ choice.value = choiceValue;
35
+ if (description)
36
+ choice.description = description;
37
+ return [choice];
38
+ });
39
+ return choices.length > 0 ? choices : undefined;
40
+ }
41
+ function normalizeRuntimeInputNative(value) {
42
+ if (!isRecord(value))
43
+ return undefined;
44
+ const native = {};
45
+ for (const key of ['runtime', 'method', 'requestId', 'sessionKey', 'turnId']) {
46
+ const normalized = normalizeString(value[key], 256);
47
+ if (normalized)
48
+ native[key] = normalized;
49
+ }
50
+ if (isRecord(value.handles)) {
51
+ const handles = {};
52
+ for (const [key, raw] of Object.entries(value.handles).slice(0, 16)) {
53
+ if (!/^[a-zA-Z0-9_.:-]{1,80}$/.test(key))
54
+ continue;
55
+ const normalized = normalizeString(raw, 256);
56
+ if (normalized)
57
+ handles[key] = normalized;
58
+ }
59
+ if (Object.keys(handles).length > 0)
60
+ native.handles = handles;
61
+ }
62
+ return Object.keys(native).length > 0 ? native : undefined;
63
+ }
64
+ function assertNoSensitiveRuntimeInputPayload(value) {
65
+ return !('value' in value)
66
+ && !('answer' in value)
67
+ && !('password' in value)
68
+ && !('secret' in value)
69
+ && !('rawValue' in value);
70
+ }
1
71
  export function buildQuestionRequest(questionId, questions) {
2
72
  const text = questions.length === 1
3
73
  ? questions[0]?.question || 'Question'
@@ -43,3 +113,131 @@ export function buildPlanApprovalReply(planId, decision, feedback) {
43
113
  },
44
114
  };
45
115
  }
116
+ export function buildRuntimeInputRequest(inputId, input) {
117
+ const title = input.title?.trim() || (input.kind === 'sudo'
118
+ ? 'Sudo password required'
119
+ : input.kind === 'secret'
120
+ ? 'Secret required'
121
+ : 'Input required');
122
+ return {
123
+ text: title,
124
+ metadata: {
125
+ type: 'runtime_input_request',
126
+ inputId,
127
+ kind: input.kind,
128
+ prompt: input.prompt.slice(0, 1000),
129
+ title: title.slice(0, 120),
130
+ ...(input.choices?.length ? { choices: input.choices.slice(0, 12) } : {}),
131
+ ...(input.secretName ? { secretName: input.secretName.slice(0, 120) } : {}),
132
+ ...(input.native ? { native: input.native } : {}),
133
+ expiresAt: input.expiresAt,
134
+ ...(input.sensitive ? { sensitive: true } : {}),
135
+ },
136
+ };
137
+ }
138
+ export function buildRuntimeInputReply(inputId, status, details) {
139
+ const answerSummary = details?.sensitive ? undefined : details?.answerSummary?.trim().slice(0, 500);
140
+ return {
141
+ text: status === 'submitted' ? 'Submitted' : 'Cancelled',
142
+ metadata: {
143
+ type: 'runtime_input_reply',
144
+ inputId,
145
+ ...(details?.kind ? { kind: details.kind } : {}),
146
+ status,
147
+ ...(answerSummary ? { answerSummary } : {}),
148
+ ...(details?.sensitive ? { sensitive: true } : {}),
149
+ },
150
+ };
151
+ }
152
+ export function buildRuntimeInputOutcome(inputId, status, details) {
153
+ return {
154
+ text: status === 'timeout'
155
+ ? 'Input request expired'
156
+ : status === 'cancelled'
157
+ ? 'Input request cancelled'
158
+ : 'Input request resolved',
159
+ metadata: {
160
+ type: 'runtime_input_outcome',
161
+ inputId,
162
+ ...(details?.kind ? { kind: details.kind } : {}),
163
+ status,
164
+ ...(details?.reason ? { reason: details.reason } : {}),
165
+ },
166
+ };
167
+ }
168
+ export function parseRuntimeInputRequestMetadata(value) {
169
+ if (!isRecord(value) || value.type !== 'runtime_input_request')
170
+ return null;
171
+ if (!assertNoSensitiveRuntimeInputPayload(value))
172
+ return null;
173
+ const inputId = normalizeString(value.inputId, 128);
174
+ const kind = normalizeRuntimeInputKind(value.kind);
175
+ const prompt = normalizeString(value.prompt, 1000);
176
+ const expiresAt = normalizeString(value.expiresAt, 128);
177
+ if (!inputId || !kind || !prompt || !expiresAt)
178
+ return null;
179
+ const expiresMs = Date.parse(expiresAt);
180
+ if (!Number.isFinite(expiresMs))
181
+ return null;
182
+ const title = normalizeString(value.title, 120) ?? undefined;
183
+ const choices = normalizeRuntimeInputChoices(value.choices);
184
+ const secretName = normalizeString(value.secretName, 120) ?? undefined;
185
+ const native = normalizeRuntimeInputNative(value.native);
186
+ return {
187
+ type: 'runtime_input_request',
188
+ inputId,
189
+ kind,
190
+ prompt,
191
+ ...(title ? { title } : {}),
192
+ ...(choices ? { choices } : {}),
193
+ ...(secretName ? { secretName } : {}),
194
+ ...(native ? { native } : {}),
195
+ expiresAt: new Date(expiresMs).toISOString(),
196
+ ...(value.sensitive === true ? { sensitive: true } : {}),
197
+ };
198
+ }
199
+ export function parseRuntimeInputReplyMetadata(value) {
200
+ if (!isRecord(value) || value.type !== 'runtime_input_reply')
201
+ return null;
202
+ if (!assertNoSensitiveRuntimeInputPayload(value))
203
+ return null;
204
+ const inputId = normalizeString(value.inputId, 128);
205
+ const status = normalizeRuntimeInputReplyStatus(value.status);
206
+ if (!inputId || !status)
207
+ return null;
208
+ const kind = normalizeRuntimeInputKind(value.kind) ?? undefined;
209
+ const answerSummary = value.sensitive === true ? undefined : normalizeString(value.answerSummary, 500) ?? undefined;
210
+ return {
211
+ type: 'runtime_input_reply',
212
+ inputId,
213
+ ...(kind ? { kind } : {}),
214
+ status,
215
+ ...(answerSummary ? { answerSummary } : {}),
216
+ ...(value.sensitive === true ? { sensitive: true } : {}),
217
+ };
218
+ }
219
+ export function parseRuntimeInputOutcomeMetadata(value) {
220
+ if (!isRecord(value) || value.type !== 'runtime_input_outcome')
221
+ return null;
222
+ if (!assertNoSensitiveRuntimeInputPayload(value))
223
+ return null;
224
+ const inputId = normalizeString(value.inputId, 128);
225
+ const status = normalizeRuntimeInputResolutionStatus(value.status);
226
+ if (!inputId || !status)
227
+ return null;
228
+ const kind = normalizeRuntimeInputKind(value.kind) ?? undefined;
229
+ const reason = value.reason === 'submitted'
230
+ || value.reason === 'cancelled'
231
+ || value.reason === 'timeout'
232
+ || value.reason === 'expired'
233
+ || value.reason === 'interrupted'
234
+ ? value.reason
235
+ : undefined;
236
+ return {
237
+ type: 'runtime_input_outcome',
238
+ inputId,
239
+ ...(kind ? { kind } : {}),
240
+ status,
241
+ ...(reason ? { reason } : {}),
242
+ };
243
+ }
@@ -1,5 +1,6 @@
1
1
  import type { ExecutionEnvironmentMode } from './execution-environment-mode.js';
2
2
  import { type AgentClientType, type CanonControlDescriptor, type CanonRuntimeActionDescriptor, type CanonRuntimeCommandDescriptor, type CanonRuntimeDescriptor, type CanonRuntimeStreamingMode, type CanonWorkspaceRootMetadata, type ModelOption, type PermissionModeOption, type WorkspaceOption } from './types.js';
3
+ import type { CanonRuntimePresentationPolicy } from './types.js';
3
4
  import type { HostAdmissionActionCapabilities } from './turn-protocol.js';
4
5
  export declare const CLAUDE_EFFORT_OPTIONS: readonly [{
5
6
  readonly value: "low";
@@ -51,4 +52,5 @@ export declare function buildFirstPartyCodingRuntimeDescriptor(input: {
51
52
  commands?: ReadonlyArray<CanonRuntimeCommandDescriptor>;
52
53
  streamingTextMode: CanonRuntimeStreamingMode;
53
54
  admissionActions?: HostAdmissionActionCapabilities;
55
+ presentation?: CanonRuntimePresentationPolicy;
54
56
  }): CanonRuntimeDescriptor;
@@ -1,4 +1,5 @@
1
1
  import { CLAUDE_PERMISSION_MODE_OPTIONS, } from './types.js';
2
+ import { DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION } from './runtime-presentation.js';
2
3
  export const CLAUDE_EFFORT_OPTIONS = [
3
4
  { value: 'low', label: 'Low' },
4
5
  { value: 'medium', label: 'Medium' },
@@ -155,6 +156,7 @@ export function buildFirstPartyCodingRuntimeDescriptor(input) {
155
156
  supportsInterrupt: true,
156
157
  supportsInputInterrupt: true,
157
158
  streamingTextMode: input.streamingTextMode,
159
+ presentation: input.presentation ?? DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION,
158
160
  admissionActions: input.admissionActions,
159
161
  };
160
162
  }
@@ -0,0 +1,38 @@
1
+ import type { AgentRuntime, AgentSessionSnapshot, CanonRuntimeActivityItem, CanonRuntimeDescriptor, CanonRuntimeExecutionMetadata, CanonRuntimePresentationField, CanonRuntimePresentationPolicy, RuntimeInfoPayload } from './types.js';
2
+ export declare const RUNTIME_PRESENTATION_FIELDS: readonly ["model", "permissionMode", "effort", "workspace", "executionMode", "contextUsage", "cwd", "branch", "worktreePath", "workspaceRoot", "workspaceRelativePath", "fallbackReason"];
3
+ export declare const DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION: CanonRuntimePresentationPolicy;
4
+ export declare function isRuntimePresentationField(value: string): value is CanonRuntimePresentationField;
5
+ export declare function buildRuntimePresentationPolicy(input?: {
6
+ preset?: CanonRuntimePresentationPolicy['preset'];
7
+ show?: ReadonlyArray<string>;
8
+ hide?: ReadonlyArray<string>;
9
+ base?: CanonRuntimePresentationPolicy;
10
+ }): CanonRuntimePresentationPolicy;
11
+ export declare function getRuntimePresentationHint(descriptor: CanonRuntimeDescriptor | null | undefined, field: CanonRuntimePresentationField): import("./types.js").CanonRuntimePresentationHint | null;
12
+ export declare function isRuntimePresentationFieldHidden(descriptor: CanonRuntimeDescriptor | null | undefined, field: CanonRuntimePresentationField): boolean;
13
+ export declare function redactRuntimeDescriptorForConversation(descriptor: CanonRuntimeDescriptor): CanonRuntimeDescriptor;
14
+ export declare function redactRuntimeActivityItemForConversation(item: CanonRuntimeActivityItem): CanonRuntimeActivityItem | null;
15
+ export declare function redactExecutionMetadataForConversation(descriptor: CanonRuntimeDescriptor | null | undefined, execution: CanonRuntimeExecutionMetadata | null | undefined): CanonRuntimeExecutionMetadata | null;
16
+ export declare function redactRuntimeInfoForConversation<T extends Partial<Omit<RuntimeInfoPayload, 'updatedAt'>> | RuntimeInfoPayload>(payload: T, options?: {
17
+ descriptor?: CanonRuntimeDescriptor | null;
18
+ }): T;
19
+ export declare function redactAgentRuntimeForConversation(runtime: AgentRuntime): AgentRuntime;
20
+ type SessionStatePresentationLike = {
21
+ model?: unknown;
22
+ permissionMode?: unknown;
23
+ effort?: unknown;
24
+ cwd?: unknown;
25
+ executionMode?: unknown;
26
+ executionBranch?: unknown;
27
+ worktreePath?: unknown;
28
+ executionFallbackReason?: unknown;
29
+ contextUsage?: unknown;
30
+ availableModels?: unknown;
31
+ runtimeControlValues?: Record<string, unknown>;
32
+ controlState?: Record<string, unknown>;
33
+ };
34
+ export declare function redactSessionStateForConversation<T extends SessionStatePresentationLike>(descriptor: CanonRuntimeDescriptor | null | undefined, state: T): T;
35
+ export declare function redactAgentSessionSnapshotForConversation(descriptor: CanonRuntimeDescriptor | null | undefined, snapshot: Partial<AgentSessionSnapshot> & Record<string, unknown>, options?: {
36
+ patch?: boolean;
37
+ }): Partial<AgentSessionSnapshot> & Record<string, unknown>;
38
+ export {};
@@ -0,0 +1,441 @@
1
+ const MINIMAL_HIDDEN_FIELDS = new Set([
2
+ 'model',
3
+ 'permissionMode',
4
+ 'effort',
5
+ 'workspace',
6
+ 'contextUsage',
7
+ 'cwd',
8
+ 'branch',
9
+ 'worktreePath',
10
+ 'workspaceRoot',
11
+ 'workspaceRelativePath',
12
+ 'fallbackReason',
13
+ ]);
14
+ export const RUNTIME_PRESENTATION_FIELDS = [
15
+ 'model',
16
+ 'permissionMode',
17
+ 'effort',
18
+ 'workspace',
19
+ 'executionMode',
20
+ 'contextUsage',
21
+ 'cwd',
22
+ 'branch',
23
+ 'worktreePath',
24
+ 'workspaceRoot',
25
+ 'workspaceRelativePath',
26
+ 'fallbackReason',
27
+ ];
28
+ export const DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION = {
29
+ preset: 'normal',
30
+ fields: {
31
+ cwd: { visibility: 'hidden' },
32
+ worktreePath: { visibility: 'hidden' },
33
+ workspaceRoot: { visibility: 'hidden' },
34
+ },
35
+ };
36
+ export function isRuntimePresentationField(value) {
37
+ return RUNTIME_PRESENTATION_FIELDS.includes(value);
38
+ }
39
+ export function buildRuntimePresentationPolicy(input = {}) {
40
+ const preset = input.preset ?? input.base?.preset ?? 'normal';
41
+ const fields = {
42
+ ...(preset === 'full' ? {} : input.base?.fields ?? {}),
43
+ };
44
+ for (const field of input.show ?? []) {
45
+ if (!isRuntimePresentationField(field))
46
+ continue;
47
+ fields[field] = {
48
+ ...(fields[field] ?? {}),
49
+ visibility: 'conversation',
50
+ };
51
+ }
52
+ for (const field of input.hide ?? []) {
53
+ if (!isRuntimePresentationField(field))
54
+ continue;
55
+ fields[field] = {
56
+ ...(fields[field] ?? {}),
57
+ visibility: 'hidden',
58
+ };
59
+ }
60
+ return {
61
+ preset,
62
+ fields,
63
+ };
64
+ }
65
+ function hasOwn(value, key) {
66
+ return Object.prototype.hasOwnProperty.call(value, key);
67
+ }
68
+ function cloneDefined(value) {
69
+ return Object.fromEntries(Object.entries(value).filter(([, entryValue]) => entryValue !== undefined));
70
+ }
71
+ export function getRuntimePresentationHint(descriptor, field) {
72
+ return descriptor?.presentation?.fields?.[field] ?? null;
73
+ }
74
+ export function isRuntimePresentationFieldHidden(descriptor, field) {
75
+ const policy = descriptor?.presentation;
76
+ const hint = policy?.fields?.[field];
77
+ if (hint?.visibility === 'conversation')
78
+ return false;
79
+ if (hint?.visibility === 'hidden')
80
+ return true;
81
+ return policy?.preset === 'minimal' && MINIMAL_HIDDEN_FIELDS.has(field);
82
+ }
83
+ function isRuntimeItemHidden(item) {
84
+ return item?.visibility === 'hidden';
85
+ }
86
+ function isRequiredSetupControl(control) {
87
+ return control.selectionPolicy === 'required_explicit'
88
+ && (control.availability === 'setup' || control.availability === 'setup_and_live');
89
+ }
90
+ function shouldHideControlValue(descriptor, control) {
91
+ if (isRuntimeItemHidden(control) || control.sensitive)
92
+ return true;
93
+ const field = control.id;
94
+ const hidden = isRuntimePresentationFieldHidden(descriptor, field);
95
+ return hidden && !isRequiredSetupControl(control);
96
+ }
97
+ function hiddenControlValueIds(descriptor) {
98
+ const controls = [
99
+ ...(descriptor?.coreControls ?? []),
100
+ ...(descriptor?.runtimeControls ?? []),
101
+ ];
102
+ return new Set(controls
103
+ .filter((control) => shouldHideControlValue(descriptor, control))
104
+ .map((control) => control.id));
105
+ }
106
+ function redactControlValueMap(descriptor, values, options = {}) {
107
+ if (!values)
108
+ return values;
109
+ const hiddenIds = hiddenControlValueIds(descriptor);
110
+ if (hiddenIds.size === 0)
111
+ return values;
112
+ const redacted = { ...values };
113
+ for (const id of hiddenIds) {
114
+ if (!hasOwn(redacted, id))
115
+ continue;
116
+ if (options.patch) {
117
+ redacted[id] = null;
118
+ }
119
+ else {
120
+ delete redacted[id];
121
+ }
122
+ }
123
+ return redacted;
124
+ }
125
+ function redactSensitiveValue(value) {
126
+ void value;
127
+ return 'Hidden';
128
+ }
129
+ function redactControl(descriptor, control) {
130
+ if (isRuntimeItemHidden(control))
131
+ return null;
132
+ const field = control.id;
133
+ const hidden = isRuntimePresentationFieldHidden(descriptor, field);
134
+ if (hidden && !isRequiredSetupControl(control))
135
+ return null;
136
+ if (!control.sensitive)
137
+ return control;
138
+ return cloneDefined({
139
+ ...control,
140
+ defaultValue: null,
141
+ options: control.options?.map((option) => ({
142
+ value: option.value,
143
+ label: redactSensitiveValue(option.label),
144
+ })),
145
+ });
146
+ }
147
+ function redactAction(action) {
148
+ if (isRuntimeItemHidden(action))
149
+ return null;
150
+ if (!action.sensitive)
151
+ return action;
152
+ return cloneDefined({
153
+ ...action,
154
+ description: action.description ? redactSensitiveValue(action.description) : undefined,
155
+ });
156
+ }
157
+ function redactWorkspaceOption(descriptor, option) {
158
+ const hideRoot = isRuntimePresentationFieldHidden(descriptor, 'workspaceRoot');
159
+ const hideRelative = isRuntimePresentationFieldHidden(descriptor, 'workspaceRelativePath');
160
+ return cloneDefined({
161
+ ...option,
162
+ ...(hideRoot ? { workspaceRootId: undefined } : {}),
163
+ ...(hideRelative ? { workspaceRelativePath: undefined } : {}),
164
+ });
165
+ }
166
+ export function redactRuntimeDescriptorForConversation(descriptor) {
167
+ const coreControls = (descriptor.coreControls ?? [])
168
+ .map((control) => redactControl(descriptor, control))
169
+ .filter((control) => Boolean(control))
170
+ .map((control) => control.id === 'workspace'
171
+ ? {
172
+ ...control,
173
+ options: control.options?.map((option) => redactWorkspaceOption(descriptor, option)),
174
+ }
175
+ : control);
176
+ const runtimeControls = descriptor.runtimeControls?.map((control) => redactControl(descriptor, control))
177
+ .filter((control) => Boolean(control));
178
+ const commands = descriptor.commands?.map((command) => redactAction(command))
179
+ .filter((command) => Boolean(command));
180
+ const actions = descriptor.actions?.map((action) => redactAction(action))
181
+ .filter((action) => Boolean(action));
182
+ return cloneDefined({
183
+ ...descriptor,
184
+ coreControls,
185
+ runtimeControls,
186
+ commands,
187
+ actions,
188
+ workspaceRoots: isRuntimePresentationFieldHidden(descriptor, 'workspaceRoot')
189
+ ? []
190
+ : descriptor.workspaceRoots,
191
+ writableRoots: isRuntimePresentationFieldHidden(descriptor, 'workspaceRoot')
192
+ ? []
193
+ : descriptor.writableRoots,
194
+ });
195
+ }
196
+ function redactStatusItem(item) {
197
+ if (isRuntimeItemHidden(item))
198
+ return null;
199
+ if (!item.sensitive)
200
+ return item;
201
+ return {
202
+ ...item,
203
+ value: redactSensitiveValue(item.value),
204
+ tone: item.tone ?? 'warning',
205
+ };
206
+ }
207
+ function redactFact(item) {
208
+ if (isRuntimeItemHidden(item))
209
+ return null;
210
+ if (!item.sensitive)
211
+ return item;
212
+ return {
213
+ ...item,
214
+ value: redactSensitiveValue(item.value),
215
+ tone: item.tone ?? 'warning',
216
+ copyable: false,
217
+ };
218
+ }
219
+ function redactInventoryEntry(entry) {
220
+ if (isRuntimeItemHidden(entry))
221
+ return null;
222
+ if (!entry.sensitive)
223
+ return entry;
224
+ return cloneDefined({
225
+ ...entry,
226
+ label: redactSensitiveValue(entry.label),
227
+ description: entry.description ? redactSensitiveValue(entry.description) : undefined,
228
+ });
229
+ }
230
+ function redactInventory(inventory) {
231
+ if (isRuntimeItemHidden(inventory))
232
+ return null;
233
+ const entries = (inventory.entries ?? [])
234
+ .map(redactInventoryEntry)
235
+ .filter((entry) => Boolean(entry));
236
+ if (!inventory.sensitive) {
237
+ return {
238
+ ...inventory,
239
+ entries,
240
+ };
241
+ }
242
+ return {
243
+ ...inventory,
244
+ entries: [],
245
+ label: redactSensitiveValue(inventory.label),
246
+ };
247
+ }
248
+ export function redactRuntimeActivityItemForConversation(item) {
249
+ if (isRuntimeItemHidden(item))
250
+ return null;
251
+ const actions = item.actions
252
+ ?.map((action) => redactAction(action))
253
+ .filter((action) => Boolean(action));
254
+ if (!item.sensitive) {
255
+ return cloneDefined({
256
+ ...item,
257
+ actions,
258
+ });
259
+ }
260
+ return cloneDefined({
261
+ ...item,
262
+ title: redactSensitiveValue(item.title),
263
+ summary: item.summary ? redactSensitiveValue(item.summary) : undefined,
264
+ detail: item.detail ? redactSensitiveValue(item.detail) : undefined,
265
+ progressText: item.progressText ? redactSensitiveValue(item.progressText) : undefined,
266
+ actions,
267
+ });
268
+ }
269
+ export function redactExecutionMetadataForConversation(descriptor, execution) {
270
+ if (!execution)
271
+ return null;
272
+ const redacted = cloneDefined({
273
+ ...execution,
274
+ resolvedWorkspaceLabel: isRuntimePresentationFieldHidden(descriptor, 'workspace')
275
+ ? undefined
276
+ : execution.resolvedWorkspaceLabel,
277
+ resolvedCwd: isRuntimePresentationFieldHidden(descriptor, 'cwd')
278
+ ? undefined
279
+ : execution.resolvedCwd,
280
+ workspaceRootId: isRuntimePresentationFieldHidden(descriptor, 'workspaceRoot')
281
+ ? undefined
282
+ : execution.workspaceRootId,
283
+ workspaceRelativePath: isRuntimePresentationFieldHidden(descriptor, 'workspaceRelativePath')
284
+ ? undefined
285
+ : execution.workspaceRelativePath,
286
+ executionMode: isRuntimePresentationFieldHidden(descriptor, 'executionMode')
287
+ ? undefined
288
+ : execution.executionMode,
289
+ executionBranch: isRuntimePresentationFieldHidden(descriptor, 'branch')
290
+ ? undefined
291
+ : execution.executionBranch,
292
+ worktreePath: isRuntimePresentationFieldHidden(descriptor, 'worktreePath')
293
+ ? undefined
294
+ : execution.worktreePath,
295
+ fallbackReason: isRuntimePresentationFieldHidden(descriptor, 'fallbackReason')
296
+ ? undefined
297
+ : execution.fallbackReason,
298
+ });
299
+ return Object.keys(redacted).length > 0 ? redacted : null;
300
+ }
301
+ export function redactRuntimeInfoForConversation(payload, options = {}) {
302
+ const descriptor = payload.descriptor
303
+ ? redactRuntimeDescriptorForConversation(payload.descriptor)
304
+ : payload.descriptor;
305
+ const policyDescriptor = options.descriptor ?? payload.descriptor ?? descriptor;
306
+ return cloneDefined({
307
+ ...payload,
308
+ descriptor,
309
+ facts: payload.facts
310
+ ?.map(redactFact)
311
+ .filter((fact) => Boolean(fact)),
312
+ statusItems: payload.statusItems
313
+ ?.map(redactStatusItem)
314
+ .filter((item) => Boolean(item)),
315
+ inventories: payload.inventories
316
+ ?.map(redactInventory)
317
+ .filter((inventory) => Boolean(inventory)),
318
+ ...(hasOwn(payload, 'execution')
319
+ ? { execution: redactExecutionMetadataForConversation(policyDescriptor, payload.execution) }
320
+ : {}),
321
+ });
322
+ }
323
+ export function redactAgentRuntimeForConversation(runtime) {
324
+ const descriptor = runtime.runtimeDescriptor;
325
+ const redactedDescriptor = descriptor
326
+ ? redactRuntimeDescriptorForConversation(descriptor)
327
+ : descriptor;
328
+ return cloneDefined({
329
+ ...runtime,
330
+ runtimeDescriptor: redactedDescriptor,
331
+ defaultModel: isRuntimePresentationFieldHidden(descriptor, 'model')
332
+ ? undefined
333
+ : runtime.defaultModel,
334
+ availableModels: isRuntimePresentationFieldHidden(descriptor, 'model')
335
+ ? undefined
336
+ : runtime.availableModels,
337
+ defaultPermissionMode: isRuntimePresentationFieldHidden(descriptor, 'permissionMode')
338
+ ? undefined
339
+ : runtime.defaultPermissionMode,
340
+ availablePermissionModes: isRuntimePresentationFieldHidden(descriptor, 'permissionMode')
341
+ ? undefined
342
+ : runtime.availablePermissionModes,
343
+ defaultWorkspaceId: isRuntimePresentationFieldHidden(descriptor, 'workspace')
344
+ ? undefined
345
+ : runtime.defaultWorkspaceId,
346
+ availableWorkspaces: isRuntimePresentationFieldHidden(descriptor, 'workspace')
347
+ ? undefined
348
+ : runtime.availableWorkspaces,
349
+ defaultExecutionMode: isRuntimePresentationFieldHidden(descriptor, 'executionMode')
350
+ ? undefined
351
+ : runtime.defaultExecutionMode,
352
+ availableExecutionModes: isRuntimePresentationFieldHidden(descriptor, 'executionMode')
353
+ ? undefined
354
+ : runtime.availableExecutionModes,
355
+ });
356
+ }
357
+ export function redactSessionStateForConversation(descriptor, state) {
358
+ return cloneDefined({
359
+ ...state,
360
+ model: isRuntimePresentationFieldHidden(descriptor, 'model') ? undefined : state.model,
361
+ permissionMode: isRuntimePresentationFieldHidden(descriptor, 'permissionMode')
362
+ ? undefined
363
+ : state.permissionMode,
364
+ effort: isRuntimePresentationFieldHidden(descriptor, 'effort') ? undefined : state.effort,
365
+ cwd: isRuntimePresentationFieldHidden(descriptor, 'cwd') ? undefined : state.cwd,
366
+ executionMode: isRuntimePresentationFieldHidden(descriptor, 'executionMode')
367
+ ? undefined
368
+ : state.executionMode,
369
+ executionBranch: isRuntimePresentationFieldHidden(descriptor, 'branch')
370
+ ? undefined
371
+ : state.executionBranch,
372
+ worktreePath: isRuntimePresentationFieldHidden(descriptor, 'worktreePath')
373
+ ? undefined
374
+ : state.worktreePath,
375
+ executionFallbackReason: isRuntimePresentationFieldHidden(descriptor, 'fallbackReason')
376
+ ? undefined
377
+ : state.executionFallbackReason,
378
+ contextUsage: isRuntimePresentationFieldHidden(descriptor, 'contextUsage')
379
+ ? undefined
380
+ : state.contextUsage,
381
+ availableModels: isRuntimePresentationFieldHidden(descriptor, 'model')
382
+ ? undefined
383
+ : state.availableModels,
384
+ runtimeControlValues: redactControlValueMap(descriptor, state.runtimeControlValues),
385
+ controlState: redactControlValueMap(descriptor, state.controlState),
386
+ });
387
+ }
388
+ export function redactAgentSessionSnapshotForConversation(descriptor, snapshot, options = {}) {
389
+ const hiddenValue = options.patch ? null : undefined;
390
+ const redacted = {
391
+ ...snapshot,
392
+ model: isRuntimePresentationFieldHidden(descriptor, 'model') ? hiddenValue : snapshot.model,
393
+ modelOptions: isRuntimePresentationFieldHidden(descriptor, 'model') ? hiddenValue : snapshot.modelOptions,
394
+ permissionMode: isRuntimePresentationFieldHidden(descriptor, 'permissionMode') ? hiddenValue : snapshot.permissionMode,
395
+ permissionModeOptions: isRuntimePresentationFieldHidden(descriptor, 'permissionMode') ? hiddenValue : snapshot.permissionModeOptions,
396
+ effort: isRuntimePresentationFieldHidden(descriptor, 'effort') ? hiddenValue : snapshot.effort,
397
+ workspaceId: isRuntimePresentationFieldHidden(descriptor, 'workspace') ? hiddenValue : snapshot.workspaceId,
398
+ workspaceOptions: isRuntimePresentationFieldHidden(descriptor, 'workspace') ? hiddenValue : snapshot.workspaceOptions,
399
+ executionMode: isRuntimePresentationFieldHidden(descriptor, 'executionMode') ? hiddenValue : snapshot.executionMode,
400
+ availableExecutionModes: isRuntimePresentationFieldHidden(descriptor, 'executionMode') ? hiddenValue : snapshot.availableExecutionModes,
401
+ executionBranch: isRuntimePresentationFieldHidden(descriptor, 'branch') ? hiddenValue : snapshot.executionBranch,
402
+ resolvedWorkspaceLabel: isRuntimePresentationFieldHidden(descriptor, 'workspace') ? hiddenValue : snapshot.resolvedWorkspaceLabel,
403
+ resolvedCwd: isRuntimePresentationFieldHidden(descriptor, 'cwd') ? hiddenValue : snapshot.resolvedCwd,
404
+ worktreePath: isRuntimePresentationFieldHidden(descriptor, 'worktreePath') ? hiddenValue : snapshot.worktreePath,
405
+ executionFallbackReason: isRuntimePresentationFieldHidden(descriptor, 'fallbackReason') ? hiddenValue : snapshot.executionFallbackReason,
406
+ contextUsage: isRuntimePresentationFieldHidden(descriptor, 'contextUsage') ? hiddenValue : snapshot.contextUsage,
407
+ runtimeControlValues: redactControlValueMap(descriptor, snapshot.runtimeControlValues, options),
408
+ };
409
+ if (redacted.runtimeDescriptor) {
410
+ redacted.runtimeDescriptor = redactRuntimeDescriptorForConversation(redacted.runtimeDescriptor);
411
+ }
412
+ if (redacted.runtimeInfo) {
413
+ redacted.runtimeInfo = redactRuntimeInfoForConversation(redacted.runtimeInfo);
414
+ }
415
+ if (!redacted.controlState)
416
+ return cloneDefined(redacted);
417
+ const controlState = { ...redacted.controlState };
418
+ const hiddenIds = hiddenControlValueIds(descriptor);
419
+ for (const field of ['model', 'permissionMode', 'effort', 'workspace', 'executionMode']) {
420
+ if (isRuntimePresentationFieldHidden(descriptor, field) && hasOwn(controlState, field)) {
421
+ if (options.patch) {
422
+ controlState[field] = null;
423
+ }
424
+ else {
425
+ delete controlState[field];
426
+ }
427
+ }
428
+ }
429
+ for (const id of hiddenIds) {
430
+ if (!hasOwn(controlState, id))
431
+ continue;
432
+ if (options.patch) {
433
+ controlState[id] = null;
434
+ }
435
+ else {
436
+ delete controlState[id];
437
+ }
438
+ }
439
+ redacted.controlState = controlState;
440
+ return cloneDefined(redacted);
441
+ }
@@ -1,4 +1,5 @@
1
- import { clearRuntimeInfo, clearRuntimeActivity, clearSessionState, clearTurnState, patchAgentSessionSnapshot, patchRuntimeInfo, readRuntimeActivity, removeRuntimeActivityItem, rtdbWrite, writeRuntimeActivity, writeRuntimeInfo, writeSessionState, writeTurnState, } from './rtdb-rest.js';
1
+ import { redactAgentRuntimeForConversation, redactAgentSessionSnapshotForConversation, isRuntimePresentationFieldHidden, redactRuntimeActivityItemForConversation, redactRuntimeInfoForConversation, redactSessionStateForConversation, } from './runtime-presentation.js';
2
+ import { clearRuntimeInfo, clearRuntimeActivity, clearSessionState, clearTurnState, patchAgentSessionSnapshot, patchRuntimeInfo, readRuntimeActivity, removeRuntimeActivityItem, rtdbRead, rtdbWrite, writeRuntimeActivity, writeRuntimeInfo, writeSessionState, writeTurnState, } from './rtdb-rest.js';
2
3
  const SERVER_TIMESTAMP = { '.sv': 'timestamp' };
3
4
  const MAX_RUNTIME_ACTIVITY_ITEMS = 50;
4
5
  const TERMINAL_RUNTIME_ACTIVITY_CLEAR_MS = 60_000;
@@ -6,9 +7,60 @@ const TERMINAL_RUNTIME_ACTIVITY_STATUSES = new Set(['completed', 'failed', 'bloc
6
7
  function isTerminalRuntimeActivity(item) {
7
8
  return TERMINAL_RUNTIME_ACTIVITY_STATUSES.has(item.status);
8
9
  }
10
+ function hasNonEmptyArray(value) {
11
+ return Array.isArray(value) && value.length > 0;
12
+ }
13
+ function hasEnabledAdmissionActions(value) {
14
+ if (!value || typeof value !== 'object' || Array.isArray(value))
15
+ return false;
16
+ return Object.values(value).some((enabled) => enabled === true);
17
+ }
18
+ function hasPreservableRuntimeState(value) {
19
+ if (!value || typeof value !== 'object' || Array.isArray(value))
20
+ return false;
21
+ const descriptor = value.runtimeDescriptor;
22
+ if (!descriptor || typeof descriptor !== 'object' || Array.isArray(descriptor))
23
+ return false;
24
+ const runtimeDescriptor = descriptor;
25
+ return hasNonEmptyArray(runtimeDescriptor.coreControls)
26
+ || hasNonEmptyArray(runtimeDescriptor.runtimeControls)
27
+ || hasNonEmptyArray(runtimeDescriptor.commands)
28
+ || hasNonEmptyArray(runtimeDescriptor.actions)
29
+ || hasNonEmptyArray(runtimeDescriptor.workspaceRoots)
30
+ || hasNonEmptyArray(runtimeDescriptor.writableRoots)
31
+ || hasEnabledAdmissionActions(runtimeDescriptor.admissionActions)
32
+ || runtimeDescriptor.streamingTextMode === 'delta'
33
+ || runtimeDescriptor.streamingTextMode === 'block';
34
+ }
9
35
  export function createRuntimeStatePublisher(options) {
10
36
  const { agentId, clientType, hostMode, rtdb } = options;
11
37
  const writePath = (path, data) => (rtdb ? rtdb.write(path, data) : rtdbWrite(path, data));
38
+ const readPath = (path) => (rtdb ? rtdb.read(path) : rtdbRead(path));
39
+ let lastRawRuntime = null;
40
+ let lastPublicRuntime = null;
41
+ function currentDescriptor() {
42
+ return lastRawRuntime?.runtimeDescriptor ?? null;
43
+ }
44
+ function hasHiddenSessionStateField(descriptor) {
45
+ if (!descriptor)
46
+ return false;
47
+ const controls = [
48
+ ...(descriptor.coreControls ?? []),
49
+ ...(descriptor.runtimeControls ?? []),
50
+ ];
51
+ return [
52
+ 'model',
53
+ 'permissionMode',
54
+ 'effort',
55
+ 'cwd',
56
+ 'executionMode',
57
+ 'branch',
58
+ 'worktreePath',
59
+ 'fallbackReason',
60
+ 'contextUsage',
61
+ ].some((field) => isRuntimePresentationFieldHidden(descriptor, field))
62
+ || controls.some((control) => control.visibility === 'hidden' || control.sensitive === true);
63
+ }
12
64
  const readRuntimeActivityPath = (conversationId) => (rtdb
13
65
  ? rtdb.readRuntimeActivity(conversationId, agentId)
14
66
  : readRuntimeActivity(conversationId, agentId));
@@ -36,20 +88,56 @@ export function createRuntimeStatePublisher(options) {
36
88
  }
37
89
  return {
38
90
  async publishAgentRuntime(runtime) {
39
- await writePath(`/agent-runtime/${agentId}`, {
91
+ const rawRuntime = {
40
92
  clientType,
41
93
  hostMode,
42
94
  ...runtime,
95
+ };
96
+ const publicPayload = {
97
+ ...redactAgentRuntimeForConversation(rawRuntime),
43
98
  updatedAt: SERVER_TIMESTAMP,
44
- });
99
+ };
100
+ lastRawRuntime = rawRuntime;
101
+ lastPublicRuntime = publicPayload;
102
+ await writePath(`/agent-runtime/${agentId}`, publicPayload);
45
103
  },
46
104
  async clearAgentRuntime() {
47
- await writePath(`/agent-runtime/${agentId}`, null);
105
+ const path = `/agent-runtime/${agentId}`;
106
+ const current = lastPublicRuntime ?? await readPath(path).catch(() => null);
107
+ if (hasPreservableRuntimeState(current)) {
108
+ await writePath(path, {
109
+ ...current,
110
+ updatedAt: 0,
111
+ });
112
+ return;
113
+ }
114
+ await writePath(path, null);
48
115
  },
49
116
  async writeSessionState(conversationId, state) {
117
+ const descriptor = currentDescriptor();
118
+ const publicState = redactSessionStateForConversation(descriptor, state);
50
119
  await (rtdb
51
- ? rtdb.writeSessionState(conversationId, agentId, state)
52
- : writeSessionState(conversationId, agentId, state));
120
+ ? rtdb.writeSessionState(conversationId, agentId, publicState)
121
+ : writeSessionState(conversationId, agentId, publicState));
122
+ if (hasHiddenSessionStateField(descriptor)) {
123
+ const clearingPatch = redactAgentSessionSnapshotForConversation(descriptor, {
124
+ model: state.model,
125
+ modelOptions: state.availableModels,
126
+ permissionMode: state.permissionMode,
127
+ effort: state.effort,
128
+ resolvedCwd: state.cwd,
129
+ executionMode: state.executionMode,
130
+ executionBranch: state.executionBranch,
131
+ worktreePath: state.worktreePath,
132
+ executionFallbackReason: state.executionFallbackReason,
133
+ contextUsage: state.contextUsage,
134
+ runtimeControlValues: state.runtimeControlValues,
135
+ controlState: state.controlState,
136
+ }, { patch: true });
137
+ await (rtdb
138
+ ? rtdb.patchAgentSessionSnapshot(conversationId, agentId, clearingPatch)
139
+ : patchAgentSessionSnapshot(conversationId, agentId, clearingPatch));
140
+ }
53
141
  },
54
142
  async clearSessionState(conversationId) {
55
143
  await (rtdb
@@ -67,19 +155,22 @@ export function createRuntimeStatePublisher(options) {
67
155
  : clearTurnState(conversationId, agentId));
68
156
  },
69
157
  async patchAgentSessionSnapshot(conversationId, snapshot) {
158
+ const publicSnapshot = redactAgentSessionSnapshotForConversation(currentDescriptor(), snapshot, { patch: true });
70
159
  await (rtdb
71
- ? rtdb.patchAgentSessionSnapshot(conversationId, agentId, snapshot)
72
- : patchAgentSessionSnapshot(conversationId, agentId, snapshot));
160
+ ? rtdb.patchAgentSessionSnapshot(conversationId, agentId, publicSnapshot)
161
+ : patchAgentSessionSnapshot(conversationId, agentId, publicSnapshot));
73
162
  },
74
163
  async writeRuntimeInfo(conversationId, payload) {
164
+ const publicPayload = redactRuntimeInfoForConversation(payload, { descriptor: currentDescriptor() });
75
165
  await (rtdb
76
- ? rtdb.writeRuntimeInfo(conversationId, agentId, payload)
77
- : writeRuntimeInfo(conversationId, agentId, payload));
166
+ ? rtdb.writeRuntimeInfo(conversationId, agentId, publicPayload)
167
+ : writeRuntimeInfo(conversationId, agentId, publicPayload));
78
168
  },
79
169
  async patchRuntimeInfo(conversationId, payload) {
170
+ const publicPayload = redactRuntimeInfoForConversation(payload, { descriptor: currentDescriptor() });
80
171
  await (rtdb
81
- ? rtdb.patchRuntimeInfo(conversationId, agentId, payload)
82
- : patchRuntimeInfo(conversationId, agentId, payload));
172
+ ? rtdb.patchRuntimeInfo(conversationId, agentId, publicPayload)
173
+ : patchRuntimeInfo(conversationId, agentId, publicPayload));
83
174
  },
84
175
  async clearRuntimeInfo(conversationId) {
85
176
  await (rtdb
@@ -87,9 +178,12 @@ export function createRuntimeStatePublisher(options) {
87
178
  : clearRuntimeInfo(conversationId, agentId));
88
179
  },
89
180
  async writeRuntimeActivity(conversationId, item) {
181
+ const publicItem = redactRuntimeActivityItemForConversation(item);
182
+ if (!publicItem)
183
+ return;
90
184
  const normalized = {
91
- ...item,
92
- updatedAt: item.updatedAt || Date.now(),
185
+ ...publicItem,
186
+ updatedAt: publicItem.updatedAt || Date.now(),
93
187
  };
94
188
  await (rtdb
95
189
  ? rtdb.writeRuntimeActivity(conversationId, agentId, normalized)
@@ -43,6 +43,16 @@ export const HOST_ADMISSION_ACTIONS_DISABLED = {
43
43
  function isRecord(value) {
44
44
  return typeof value === 'object' && value !== null && !Array.isArray(value);
45
45
  }
46
+ function isHiddenRuntimeCardMetadata(metadata) {
47
+ if (!isRecord(metadata) || typeof metadata.type !== 'string')
48
+ return false;
49
+ return metadata.type === 'approval_reply'
50
+ || metadata.type === 'approval_outcome'
51
+ || metadata.type === 'question_reply'
52
+ || metadata.type === 'plan_approval_reply'
53
+ || metadata.type === 'runtime_input_reply'
54
+ || metadata.type === 'runtime_input_outcome';
55
+ }
46
56
  export function normalizeTurnMetadata(metadata) {
47
57
  if (!isRecord(metadata))
48
58
  return null;
@@ -132,6 +142,9 @@ export function resolveTurnMessageSemantics(input) {
132
142
  return isTurnOpen(input.senderTurnState) ? 'progress' : 'turn_complete';
133
143
  }
134
144
  export function shouldPromoteConversationMessage(input) {
145
+ if (isHiddenRuntimeCardMetadata(input.metadata)) {
146
+ return false;
147
+ }
135
148
  return resolveTurnMessageSemantics(input) !== 'progress';
136
149
  }
137
150
  export function shouldTriggerAgentTurn(input) {
package/dist/types.d.ts CHANGED
@@ -190,7 +190,7 @@ export interface CanonResolveAdmissionResult {
190
190
  target: ResolvedAdmissionTargetSummary | null;
191
191
  admission: ResolvedTargetAdmissionPayload;
192
192
  }
193
- export type AgentClientType = 'claude-code' | 'openclaw' | 'codex' | 'generic';
193
+ export type AgentClientType = 'claude-code' | 'openclaw' | 'codex' | 'hermes' | 'generic';
194
194
  export interface ResolvedAdmission {
195
195
  discoverable: boolean;
196
196
  inboundPolicy: 'open' | 'approval-required' | 'owner-only';
@@ -216,6 +216,8 @@ export interface ModelOption {
216
216
  value: string;
217
217
  label: string;
218
218
  description?: string;
219
+ /** This option may only be selected by the agent owner or the agent itself. */
220
+ ownerOnly?: boolean;
219
221
  workspaceRootId?: string;
220
222
  workspaceRelativePath?: string;
221
223
  source?: WorkspaceOptionSource;
@@ -248,6 +250,18 @@ export type CanonControlSelectionPolicy = 'inherit' | 'required_explicit';
248
250
  export type CanonRuntimeStreamingMode = 'none' | 'status' | 'snapshot' | 'block' | 'delta';
249
251
  export type CanonRuntimeSurfaceMode = 'host' | 'channel' | 'limited_channel' | 'operator';
250
252
  export type CanonRuntimeDetailTier = 'primary' | 'detail' | 'diagnostic';
253
+ export type CanonRuntimeVisibility = 'conversation' | 'hidden';
254
+ export type CanonRuntimePresentationPreset = 'normal' | 'minimal' | 'full';
255
+ export type CanonRuntimePresentationField = 'model' | 'permissionMode' | 'effort' | 'workspace' | 'executionMode' | 'contextUsage' | 'cwd' | 'branch' | 'worktreePath' | 'workspaceRoot' | 'workspaceRelativePath' | 'fallbackReason';
256
+ export interface CanonRuntimePresentationHint {
257
+ visibility?: CanonRuntimeVisibility;
258
+ tier?: CanonRuntimeDetailTier;
259
+ sensitive?: boolean;
260
+ }
261
+ export interface CanonRuntimePresentationPolicy {
262
+ preset?: CanonRuntimePresentationPreset;
263
+ fields?: Partial<Record<CanonRuntimePresentationField, CanonRuntimePresentationHint>>;
264
+ }
251
265
  export type CanonRuntimeFactGroup = 'connection' | 'route' | 'runtime' | 'model' | 'session' | 'account' | 'limits';
252
266
  export type CanonRuntimeInventoryStatus = 'ready' | 'auth_needed' | 'unknown' | 'configured' | 'running' | 'error';
253
267
  export type CanonRuntimeStatusTone = 'default' | 'success' | 'warning' | 'danger';
@@ -293,6 +307,9 @@ export interface CanonRuntimeActionDescriptor {
293
307
  id: string;
294
308
  label: string;
295
309
  description?: string;
310
+ visibility?: CanonRuntimeVisibility;
311
+ tier?: CanonRuntimeDetailTier;
312
+ sensitive?: boolean;
296
313
  primitive?: CanonRuntimePrimitiveId;
297
314
  aliases?: ReadonlyArray<string>;
298
315
  category?: CanonRuntimeActionCategory;
@@ -317,6 +334,9 @@ export interface CanonControlDescriptor {
317
334
  liveBehavior: CanonControlLiveBehavior;
318
335
  selectionPolicy: CanonControlSelectionPolicy;
319
336
  description?: string;
337
+ visibility?: CanonRuntimeVisibility;
338
+ tier?: CanonRuntimeDetailTier;
339
+ sensitive?: boolean;
320
340
  }
321
341
  export interface CanonRuntimeDescriptor {
322
342
  coreControls: ReadonlyArray<CanonControlDescriptor>;
@@ -339,6 +359,12 @@ export interface CanonRuntimeDescriptor {
339
359
  * means activity/tool state without live assistant text.
340
360
  */
341
361
  streamingTextMode?: CanonRuntimeStreamingMode;
362
+ /**
363
+ * Runtime-owned presentation policy for built-in Canon detail fields.
364
+ * Hidden fields are redacted before public/member-readable runtime payloads
365
+ * are published; clients only render what remains.
366
+ */
367
+ presentation?: CanonRuntimePresentationPolicy;
342
368
  /**
343
369
  * Contact-graph and admission actions this runtime exposes through the
344
370
  * agent SDK. Plugins set this to advertise which tools they will surface
@@ -364,6 +390,7 @@ export interface CanonRuntimeStatusItem {
364
390
  tone?: CanonRuntimeStatusTone;
365
391
  tier?: CanonRuntimeDetailTier;
366
392
  sensitive?: boolean;
393
+ visibility?: CanonRuntimeVisibility;
367
394
  source?: RuntimeControlValueSource;
368
395
  }
369
396
  export interface CanonRuntimeFact {
@@ -372,6 +399,8 @@ export interface CanonRuntimeFact {
372
399
  value: string;
373
400
  group: CanonRuntimeFactGroup;
374
401
  tier?: CanonRuntimeDetailTier;
402
+ sensitive?: boolean;
403
+ visibility?: CanonRuntimeVisibility;
375
404
  tone?: 'neutral' | 'good' | 'warning' | 'danger';
376
405
  copyable?: boolean;
377
406
  updatedAt?: number;
@@ -390,6 +419,9 @@ export interface CanonRuntimeActivityItem {
390
419
  startedAt?: number;
391
420
  updatedAt: number;
392
421
  endedAt?: number;
422
+ visibility?: CanonRuntimeVisibility;
423
+ tier?: CanonRuntimeDetailTier;
424
+ sensitive?: boolean;
393
425
  actions?: ReadonlyArray<CanonRuntimeCommandDescriptor>;
394
426
  }
395
427
  export interface CanonRuntimeInventoryEntry {
@@ -397,12 +429,17 @@ export interface CanonRuntimeInventoryEntry {
397
429
  label: string;
398
430
  status?: CanonRuntimeInventoryStatus;
399
431
  description?: string;
432
+ tier?: CanonRuntimeDetailTier;
433
+ sensitive?: boolean;
434
+ visibility?: CanonRuntimeVisibility;
400
435
  }
401
436
  export interface CanonRuntimeInventory {
402
437
  id: string;
403
438
  label: string;
404
439
  entries: ReadonlyArray<CanonRuntimeInventoryEntry>;
405
440
  tier?: CanonRuntimeDetailTier;
441
+ sensitive?: boolean;
442
+ visibility?: CanonRuntimeVisibility;
406
443
  }
407
444
  export interface RuntimeInfoPayload {
408
445
  descriptor: CanonRuntimeDescriptor;
@@ -640,6 +677,8 @@ export interface PermissionModeOption {
640
677
  value: string;
641
678
  label: string;
642
679
  description?: string;
680
+ /** Runtime-owned risk marker; Canon enforces owner-only selection generically. */
681
+ ownerOnly?: boolean;
643
682
  }
644
683
  export declare const CLAUDE_PERMISSION_MODE_OPTIONS: readonly [{
645
684
  readonly value: "default";
@@ -653,12 +692,15 @@ export declare const CLAUDE_PERMISSION_MODE_OPTIONS: readonly [{
653
692
  }, {
654
693
  readonly value: "dontAsk";
655
694
  readonly label: "Don't ask";
695
+ readonly ownerOnly: true;
656
696
  }, {
657
697
  readonly value: "bypassPermissions";
658
698
  readonly label: "Bypass";
699
+ readonly ownerOnly: true;
659
700
  }, {
660
701
  readonly value: "auto";
661
702
  readonly label: "Auto";
703
+ readonly ownerOnly: true;
662
704
  }];
663
705
  export interface AgentRuntime {
664
706
  clientType?: AgentClientType;
package/dist/types.js CHANGED
@@ -29,6 +29,15 @@ export const AGENT_CAPABILITIES = {
29
29
  supportsQueue: true,
30
30
  supportsInterleave: false,
31
31
  },
32
+ 'hermes': {
33
+ supportsModelSwitch: false,
34
+ supportsPermissionMode: false,
35
+ supportsEffort: false,
36
+ supportsSessionState: true,
37
+ supportsInterrupt: true,
38
+ supportsQueue: true,
39
+ supportsInterleave: false,
40
+ },
32
41
  'openclaw': { ...DEFAULT_CAPABILITIES },
33
42
  'generic': { ...DEFAULT_CAPABILITIES },
34
43
  };
@@ -36,7 +45,7 @@ export const CLAUDE_PERMISSION_MODE_OPTIONS = [
36
45
  { value: 'default', label: 'Default' },
37
46
  { value: 'acceptEdits', label: 'Auto-edit' },
38
47
  { value: 'plan', label: 'Plan' },
39
- { value: 'dontAsk', label: "Don't ask" },
40
- { value: 'bypassPermissions', label: 'Bypass' },
41
- { value: 'auto', label: 'Auto' },
48
+ { value: 'dontAsk', label: "Don't ask", ownerOnly: true },
49
+ { value: 'bypassPermissions', label: 'Bypass', ownerOnly: true },
50
+ { value: 'auto', label: 'Auto', ownerOnly: true },
42
51
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/core",
3
- "version": "0.19.0",
3
+ "version": "0.19.2",
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",