import { type VcMeetingActionRecord, type VcMeetingActionRef, type VcMeetingActionSink, type VcMeetingActionTransitionResult } from './vc-meeting-action-store.js'; import { type VcMeetingDeliveryReceiptRecord, type VcMeetingMemberProjectionRecord } from './vc-meeting-delivery-store.js'; export type VcMeetingManagedActionChannel = 'text' | 'voice'; export interface VcMeetingManagedActionRequest { /** Trusted consumer-daemon identity; still checked against the local daemon. */ agentAppId: string; receiverSessionId: string; /** The stable delivery turn id. In MA-P0 this is exactly the delivery key. */ stableTurnId: string; dispatchAttempt: number; channel: VcMeetingManagedActionChannel; content: string; fallbackText?: string; /** Human-facing justification; excluded from provider input and inputHash. */ reason?: string; } export type VcMeetingActionAuthorizationDenial = 'listener_session_inactive' | 'meeting_phase_closed' | 'capability_denied' | 'not_sink_owner' | 'output_policy_denied'; export type VcMeetingActionAuthorizationDecision = { kind: 'allow'; } | { kind: 'approval'; } | { kind: 'deny'; reason: VcMeetingActionAuthorizationDenial; detail?: string; }; export interface VcMeetingActionAuthorizationContext { request: Readonly; projection: Readonly; receipt: Readonly; action: Readonly; sink: 'meeting_text' | 'meeting_voice'; } export interface VcMeetingActionGateDeps { dataDir: string; /** App id of the consumer daemon handling this trusted receiver request. */ selfAgentAppId: string; /** * Hub/runtime policy hook. It must verify the listener session/phase, the * selected sink owner + capability, and return the current output policy. */ authorize: (context: VcMeetingActionAuthorizationContext) => VcMeetingActionAuthorizationDecision | Promise; } /** * Daemon-derived identity for an explicit user IM turn routed into a meeting * receiver session. None of these fields may be accepted from model output. * The owner/member snapshots are intentionally carried with the turn so a * delayed action cannot silently inherit a newer authority generation. */ export interface VcMeetingTrustedImTurnOrigin { listenerAppId: string; meetingId: string; memberId: string; memberEpoch: number; agentAppId: string; ownerBootId: string; ownerEpoch: number; membershipGeneration: number; sinkOwnerGeneration: number; receiverSessionId: string; larkMessageId: string; } /** * A provider-neutral managed action originating from an explicit Lark IM * message. `canonicalInput` is the normalized provider payload (for example a * task ledger or `{ content }` for meeting text); transport metadata and * human-facing `reason` do not belong in it. */ export interface VcMeetingManagedImActionRequest { origin: VcMeetingTrustedImTurnOrigin; sink: VcMeetingActionSink; canonicalInput: Record; reason?: string; } export interface VcMeetingImActionAuthorizationContext { request: Readonly; projection: Readonly; action: Readonly; sink: VcMeetingActionSink; } export interface VcMeetingImActionGateDeps { dataDir: string; /** App id of the consumer daemon that authoritatively routed the IM turn. */ selfAgentAppId: string; authorize: (context: VcMeetingImActionAuthorizationContext) => VcMeetingActionAuthorizationDecision | Promise; } export interface VcMeetingApprovalRevalidationContext { projection: Readonly; action: Readonly; sink: VcMeetingActionSink; } export interface VcMeetingApprovalResolutionOptions { externalRefs?: Record; errorCode?: string; /** Re-check live listener phase/session and sink policy immediately before * an approved action is write-ahead claimed. Structural membership and * owner fences are enforced by this module before this hook runs. */ revalidate?: (context: VcMeetingApprovalRevalidationContext) => VcMeetingActionAuthorizationDecision | Promise; } export interface VcMeetingGenericProviderExecutionPlan { actionId: string; inputHash: string; providerKey: string; sink: VcMeetingActionSink; canonicalInput: Record; ambiguousRecovery: 'lookup_or_idempotent_retry' | 'manual_unknown'; } export interface VcMeetingGenericApprovalPresentationPlan { actionId: string; inputHash: string; providerKey: string; sink: VcMeetingActionSink; canonicalInput: Record; reason?: string; } export type VcMeetingImActionGateSuccessBody = { ok: true; kind: 'existing'; action: VcMeetingActionRecord; } | { ok: true; kind: 'execute'; action: VcMeetingActionRecord; plan: VcMeetingGenericProviderExecutionPlan; } | { ok: true; kind: 'needsApproval'; action: VcMeetingActionRecord; plan: VcMeetingGenericApprovalPresentationPlan; }; export type VcMeetingImActionGateResult = { status: 200 | 202; body: VcMeetingImActionGateSuccessBody; } | { status: 400 | 403 | 404 | 409 | 500 | 503; body: VcMeetingActionGateErrorBody; }; export interface VcMeetingProviderExecutionPlan { actionId: string; inputHash: string; providerKey: string; channel: VcMeetingManagedActionChannel; sink: 'meeting_text' | 'meeting_voice'; content: string; fallbackText?: string; /** Text may use its provider key for lookup/idempotent retry. Voice may not. */ ambiguousRecovery: 'lookup_or_idempotent_retry' | 'manual_unknown'; } export interface VcMeetingApprovalPresentationPlan { actionId: string; inputHash: string; providerKey: string; channel: VcMeetingManagedActionChannel; content: string; fallbackText?: string; reason?: string; } export type VcMeetingActionGateSuccessBody = { ok: true; kind: 'existing'; action: VcMeetingActionRecord; } | { ok: true; kind: 'execute'; action: VcMeetingActionRecord; plan: VcMeetingProviderExecutionPlan; } | { ok: true; kind: 'needsApproval'; action: VcMeetingActionRecord; plan: VcMeetingApprovalPresentationPlan; }; export interface VcMeetingActionGateErrorBody { ok: false; kind: 'rejected'; errorCode: string; error: string; action?: VcMeetingActionRecord; } type VcMeetingActionGateErrorResult = { status: 400 | 403 | 404 | 409 | 500 | 503; body: VcMeetingActionGateErrorBody; }; export type VcMeetingActionGateResult = { status: 200 | 202; body: VcMeetingActionGateSuccessBody; } | VcMeetingActionGateErrorResult; /** * Stable IM source key. The canonical tuple avoids delimiter ambiguity and the * 50-character namespace matches the bounded ids used by the action ledger. */ export declare function deriveVcMeetingImTurnSourceKey(receiverSessionId: string, larkMessageId: string): string; /** * Resolve, fence, authorize and write-ahead claim one managed meeting action. * Existing non-requested records are returned before current membership * fencing; this is what makes terminal/approval/provider replay deterministic * across epoch or owner changes. */ export declare function requestVcMeetingManagedAction(raw: VcMeetingManagedActionRequest, deps: VcMeetingActionGateDeps, now?: number): Promise; /** * Resolve and execute a managed action from an explicit user IM turn. * * Unlike delivery-origin actions this path has no delivery receipt or * dispatchAttempt: the durable identity is the authoritative membership * projection plus `hash(receiverSessionId, larkMessageId)`. The receiver * binding is checked before ledger lookup so a different session cannot use a * guessed message id to inspect an action. Exact action replays still return * their established lifecycle before current owner/member fencing, matching * delivery-origin replay semantics. */ export declare function requestVcMeetingManagedImAction(raw: VcMeetingManagedImActionRequest, deps: VcMeetingImActionGateDeps, now?: number): Promise; export interface VcMeetingActionFinishInput extends VcMeetingActionRef { status: 'succeeded' | 'failed' | 'unknown'; externalRefs?: Record; errorCode?: string; } /** Persist the provider terminal result after executing an `execute` plan. */ export declare function finishVcMeetingManagedActionProvider(dataDir: string, input: VcMeetingActionFinishInput, now?: number): VcMeetingActionTransitionResult; export interface VcMeetingApprovalCardFinishInput extends VcMeetingActionRef { status: 'presented' | 'failed' | 'unknown'; externalRefs?: Record; errorCode?: string; } /** Persist the approval-card provider result after a `needsApproval` plan. */ export declare function finishVcMeetingManagedApprovalCard(dataDir: string, input: VcMeetingApprovalCardFinishInput, now?: number): VcMeetingActionTransitionResult; export type VcMeetingApprovalResolutionResult = { kind: 'execute'; action: VcMeetingActionRecord; plan: VcMeetingProviderExecutionPlan; } | { kind: 'resolved' | 'existing'; action: VcMeetingActionRecord; } | { kind: 'conflict'; reason: string; action?: VcMeetingActionRecord; }; /** * Apply a human approval decision. Approval write and provider claim are both * durable before an execution plan is returned. */ export declare function resolveVcMeetingManagedActionApproval(dataDir: string, ref: VcMeetingActionRef, decision: 'approved' | 'rejected' | 'expired', opts?: VcMeetingApprovalResolutionOptions, now?: number): Promise; /** Useful to callers deciding whether an existing result is final for display. */ export declare function isVcMeetingManagedActionTerminal(record: VcMeetingActionRecord): boolean; export {}; //# sourceMappingURL=vc-meeting-action-gate.d.ts.map