Reference Implementationsadvanced
Interaction
live-session-coach
Primary Live Interaction Layer reference: interruptible text-live via ctx.live.openSession(), intent supersede, background work, and approval gates.
APIs Used
ctx.livectx.escalate()ctx.llmctx.provenanceCapabilities Required
interaction/coachlive.session.startWhat this demonstrates
- 1ctx.live.openSession({ mode: "text" }) — launch primary agent API
- 2G1: tentative intent superseded on direction change (no mutation from old hypothesis)
- 3G2: observational background work while session stays conversational
- 4G3: ctx.escalate() approval gate before consequential connector invoke
- 5Provenance for session lifecycle, intent transitions, and overrides
Source
View on GitHubtypescript
/** * Live Session Coach — Live Interaction Layer reference agent * * Canon alignment: * - Launch product API: ctx.live.openSession() (plans/humanos_live_interaction_layer_prd.md) * - Duplex is internal Conversation Channel plumbing — not the documented agent entry. * - Demonstrates golden scenarios G1–G3 for agent authors. * * G1 — Interruptible planning: supersede tentative intent on direction change * G2 — Background work while present: presence stays conversational while work runs * G3 — Approval before consequential action: escalate before connector invoke */
import { handler, withProvenanceContext } from '@human/agent-sdk';import type { ExecutionContext } from '@human/agent-sdk';import { transitionIntentStatus, assertIntentActionable, type IntentHypothesis,} from '@human/interaction';import { RunState } from '@human/core';import { randomUUID } from 'node:crypto';
export const AGENT_ID = 'live-session-coach';export const VERSION = '1.0.0';export const CAPABILITIES = [ 'live.session.start', 'live.session.intent.propose', 'live.session.work.background', 'live.session.override', 'interaction/coach',];
export interface LiveSessionTurn { utterance: string; /** G1: supersede the prior tentative intent with a new goal inferred from this turn. */ supersede?: boolean; /** G2: start background work while presence stays conversational (intent must be confirmed before connectors). */ background_work?: boolean; /** G3: consequential action label — triggers approval gate before any send. */ consequential_action?: string; /** Simulates override reflex: cancel pending approval/work. */ cancel_pending?: boolean;}
export interface LiveSessionCoachInput { mode?: 'text' | 'voice'; provider?: string; turns?: LiveSessionTurn[]; maxDurationSecs?: number;}
export interface LiveSessionCoachOutput { success: boolean; live_session_id: string; turn_count: number; intents_proposed: number; intents_superseded: number; background_work_started: boolean; approval_status: 'none' | 'pending' | 'approved' | 'rejected' | 'cancelled'; stopped_reason: 'natural_end' | 'max_duration' | 'error'; provenance_id: string;}
export async function execute( ctx: ExecutionContext, input: LiveSessionCoachInput,): Promise<LiveSessionCoachOutput> { const mode = input.mode ?? 'text'; const turns = input.turns ?? []; const maxDurationSecs = input.maxDurationSecs ?? 300;
let intentsProposed = 0; let intentsSuperseded = 0; let backgroundWorkStarted = false; let approvalStatus: LiveSessionCoachOutput['approval_status'] = 'none'; let activeIntent: IntentHypothesis | null = null; let pendingApprovalId: string | null = null; let stoppedReason: LiveSessionCoachOutput['stopped_reason'] = 'natural_end';
try { const session = await ctx.live.openSession({ mode, provider: input.provider ?? 'mock', });
ctx.log.info('LiveSession opened', { live_session_id: session.live_session_id, mode: session.mode, });
await ctx.provenance.log( withProvenanceContext(ctx, { action: 'live.session.started', status: 'success', input: { mode, provider: input.provider ?? 'mock' }, output: { live_session_id: session.live_session_id }, }), );
const deadline = Date.now() + maxDurationSecs * 1000;
for (const turn of turns) { if (Date.now() > deadline) { stoppedReason = 'max_duration'; break; }
if (turn.cancel_pending) { pendingApprovalId = null; approvalStatus = 'cancelled'; await ctx.provenance.log( withProvenanceContext(ctx, { action: 'live.session.override.cancel_pending', status: 'success', input: { utterance: turn.utterance }, output: { live_session_id: session.live_session_id }, }), ); continue; }
const inferredGoal = inferGoal(turn.utterance);
if (activeIntent && turn.supersede) { const superseded = transitionIntentStatus(activeIntent, 'superseded', { superseded_by: 'pending', }); intentsSuperseded++; await ctx.provenance.log( withProvenanceContext(ctx, { action: 'live.intent.superseded', status: 'success', input: { old_goal: activeIntent.inferred_goal, new_utterance: turn.utterance }, output: { hypothesis_id: superseded.hypothesis_id }, }), ); activeIntent = null; }
const hypothesis: IntentHypothesis = { hypothesis_id: randomUUID(), live_session_id: session.live_session_id, confidence: 0.72, inferred_goal: inferredGoal, likely_actions: inferLikelyActions(turn), risk_level: turn.consequential_action ? 'high' : 'low', requires_approval: Boolean(turn.consequential_action), required_capabilities: turn.consequential_action ? ['connector.email.send'] : [], status: 'tentative', }; activeIntent = hypothesis; intentsProposed++;
await ctx.provenance.log( withProvenanceContext(ctx, { action: 'live.intent.proposed', status: 'success', input: { utterance: turn.utterance }, output: { hypothesis_id: hypothesis.hypothesis_id, inferred_goal: inferredGoal }, }), );
if (turn.background_work) { backgroundWorkStarted = true; await ctx.provenance.log( withProvenanceContext(ctx, { action: 'live.work.background.started', status: 'success', input: { label: 'deck_analysis', work_kind: 'background_analysis' }, output: { live_session_id: session.live_session_id, run_state: RunState.Executing, }, }), ); }
if (turn.consequential_action) { const confirmed = transitionIntentStatus(hypothesis, 'confirmed'); activeIntent = confirmed; assertIntentActionable(confirmed);
const escalation = await ctx.escalate({ reason: `Consequential action requires approval: ${turn.consequential_action}`, context: { live_session_id: session.live_session_id, hypothesis_id: confirmed.hypothesis_id, action: turn.consequential_action, }, waitForDecision: false, routingMode: 'workforce_cloud', });
if (escalation.approved) { approvalStatus = 'approved'; pendingApprovalId = escalation.metadata?.provenanceId ?? null; } else if (escalation.status === 'pending') { approvalStatus = 'pending'; pendingApprovalId = escalation.metadata?.provenanceId ?? null; } else { approvalStatus = 'rejected'; }
const provenanceStatus = approvalStatus === 'approved' ? 'success' : approvalStatus === 'rejected' ? 'error' : 'started'; await ctx.provenance.log( withProvenanceContext(ctx, { action: 'live.approval.gate', status: provenanceStatus, input: { action: turn.consequential_action }, output: { approval_status: approvalStatus, approval_id: pendingApprovalId }, }), );
if (approvalStatus !== 'approved') { continue; } }
const coaching = await analyzeUtterance(ctx, turn.utterance); if (coaching) { ctx.log.info('Coaching insight', { insight: coaching }); } }
const provenanceId = await ctx.provenance.log( withProvenanceContext(ctx, { action: 'live.session.completed', status: 'success', input: { mode, turn_count: turns.length }, output: { live_session_id: session.live_session_id, intents_proposed: intentsProposed, intents_superseded: intentsSuperseded, approval_status: approvalStatus, }, }), );
return { success: true, live_session_id: session.live_session_id, turn_count: turns.length, intents_proposed: intentsProposed, intents_superseded: intentsSuperseded, background_work_started: backgroundWorkStarted, approval_status: approvalStatus, stopped_reason: stoppedReason, provenance_id: provenanceId, }; } catch (err) { ctx.log.error('Live session coach error', { error: err }); const provenanceId = await ctx.provenance.log( withProvenanceContext(ctx, { action: 'live.session.completed', status: 'error', input: { mode }, output: { error: String(err) }, }), ); return { success: false, live_session_id: 'unknown', turn_count: turns.length, intents_proposed: intentsProposed, intents_superseded: intentsSuperseded, background_work_started: backgroundWorkStarted, approval_status: approvalStatus, stopped_reason: 'error', provenance_id: provenanceId, }; }}
function inferGoal(utterance: string): string { const lower = utterance.toLowerCase(); if (lower.includes('challenge')) return 'Identify investor challenges'; if (lower.includes('deck') || lower.includes('background')) return 'Analyze presentation deck'; if (lower.includes('send') || lower.includes('email')) return 'Send revised note to investor'; if (lower.includes('prep') || lower.includes('call')) return 'Prepare for investor call'; return `Respond to: ${utterance.slice(0, 80)}`;}
function inferLikelyActions(turn: LiveSessionTurn): string[] { if (turn.consequential_action) return [turn.consequential_action]; if (turn.background_work) return ['analyze_deck', 'summarize_risks']; return ['clarify_goal', 'coach_response'];}
async function analyzeUtterance(ctx: ExecutionContext, text: string): Promise<string | null> { if (text.trim().length < 10) return null;
try { const systemPrompt = await ctx.prompts.load('core/agents/live-session-coach/system'); const result = await ctx.llm.complete({ system: systemPrompt.content, prompt: `User said: "${text}"\n\nProvide a 1-2 sentence coaching insight for a live session, or empty string if nothing useful.`, temperature: 0.4, maxTokens: 80, promptMetadata: systemPrompt.toCallMetadata(), }); const trimmed = result.content.trim(); return trimmed.length > 0 ? trimmed : null; } catch { return null; }}
export default handler({ name: AGENT_ID, id: AGENT_ID, version: VERSION, capabilities: CAPABILITIES, description: 'Reference agent for LiveSession: interruptible text-live, intent supersede, background work, and approval gates via ctx.live.', manifest: { operations: [ { name: 'coach', description: 'Open a LiveSession and demonstrate G1–G3 live interaction patterns', paramsSchema: { mode: { type: 'string', description: 'text | voice' }, provider: { type: 'string', description: 'Provider (default: mock)' }, turns: { type: 'array', description: 'Simulated conversation turns for demo/tests' }, }, resultKind: 'agent.live-session-coach.result', }, ], }, execute,});Run the tests
From monorepo root
$ pnpm test:agents:reference
$ pnpm test:agents:reference:verbose
The reference suite runs all 23 agents with createMockExecutionContext(), verifying every ctx.* API call and output shape.
See Also
SDK Reference
Patterns