Building an agent cockpit

gecx-chat-cockpit is the agent-side dual of gecx-chat. It mirrors useChatSession and ChatSession from the agent's perspective: the agent sees the customer transcript live, plus cockpit-only controls (pick up, hold, resolve, transfer, end, whisper, add note).

The SDK core stays framework-neutral. gecx-chat-cockpit and the CCaaS adapters are opt-in dependencies — gecx-chat itself imports neither.

Install

pnpm add gecx-chat gecx-chat-cockpit

Minimal example

import { useAgentSession, CockpitSurface } from 'gecx-chat-cockpit/react';
import { createMockCockpitTransport } from 'gecx-chat-cockpit/testing';

const pair = createMockCockpitTransport();

export function AgentDesk() {
  const cockpit = useAgentSession({
    identity: { agentId: 'a-101', displayName: 'Sam K.', team: 'Tier 1' },
    transport: pair.cockpit,
    audit: (event) => console.log('audit', event),
  });

  return (
    <CockpitSurface
      state={cockpit.state}
      onPickUp={cockpit.pickUp}
      onHold={cockpit.placeOnHold}
      onResume={cockpit.resumeCall}
      onComplete={cockpit.completeSession}
      onEnd={cockpit.endSession}
      onTransfer={cockpit.transferTo}
      onSend={cockpit.sendMessage}
      onAddNote={cockpit.addInternalNote}
    />
  );
}

The CockpitTransport contract

The cockpit talks to the customer-side session through a CockpitTransport:

interface CockpitTransport {
  onAction(handler: (action: HandoffAction) => void): () => void;
  onMessage(handler: (message: ChatMessage) => void): () => void;
  sendMessage(text: string, options?: { transferType?: TransferType }): Promise<void>;
  dispatchAction(action: HandoffAction): Promise<void>;
  getSnapshot?(): Promise<{ state: HandoffProtocolState; bundle: TransferContextBundle | null; messages: ChatMessage[] }>;
}

For local development and tests, createMockCockpitTransport() returns both sides of an in-process pair. For production deployments, your back-end exposes a WebSocket (or polling REST) endpoint that adapts to this shape.

Cockpit-only actions

MethodEffect
pickUp()Claim a queued/ringing transfer. First call wins.
placeOnHold()Move from connected to on_hold.
resumeCall()Move back from on_hold to connected.
transferTo(opts)End the current leg, open a new handoff REQUEST for the next agent (default: human_to_human).
completeSession(reason?)Mark the handoff resolved — emits COMPLETE protocol action and transitions to terminal completed state. Distinct from endSession. The default cockpit surface renders this as a "Resolve" button.
endSession(reason?)Terminate the connected session without resolution semantics.
sendMessage(text)Send a customer-visible reply.
addInternalNote(text)Append to the cockpit's internal notes (not customer-visible).
whisper(text)Send a supervisor-consult side-channel message.

Audit events

Every cockpit action emits a CockpitAuditEvent. Pipe these into your governance audit sink so the agent-side actions show up next to the customer-side handoff transitions:

useAgentSession({
  identity: { agentId: 'a-1' },
  transport,
  audit: (event) => sendToAuditSink(event),
});

Custom surface

<CockpitSurface> is a sensible default, but the surface is just a React component. Build your own using the cockpit.state snapshot — all you need is the AgentSessionApi interface returned by useAgentSession.

See also

Source: docs/guides/agent-cockpit.md