Skip to content
Playground

Interaction Modes

Last updated today · 794622a

Updated today

"docs(interaction): add missing feature page for @reactive-agents/interaction" · 794622a · 2026-09-06

  • ## Install
  • # or
  • ## The five modes
  • ## Provide the layer
  • ## `InteractionManager` — the unified facade
  • ## Preference learning

@reactive-agents/interaction is a standalone package for building human-in-the-loop control around an agent: named interaction modes, milestone checkpoints, an approval-gate primitive, real-time collaboration sessions, and a learner that adapts to a user’s approval patterns over time.

Terminal window
npm install @reactive-agents/interaction
# or
bun add @reactive-agents/interaction
type InteractionModeType =
| "autonomous" // Fire-and-forget: agent runs independently
| "supervised" // Checkpoints: agent pauses at milestones for approval
| "collaborative" // Real-time: agent and user work together
| "consultative" // Advisory: agent observes and suggests
| "interrogative" // Drill-down: user explores agent state/reasoning

ModeSwitcher tracks the active mode per agent and evaluates transition rules (e.g. escalate from autonomous to supervised after N consecutive errors) via InteractionConfig’s modeTransitionRules / escalationConditions.

createInteractionLayer(config?) wires all five services (InteractionManager, ModeSwitcher, NotificationService, CheckpointService, CollaborationService, PreferenceLearner) into one Layer. It requires EventBus from @reactive-agents/core.

import { Effect } from "effect"
import { createInteractionLayer, InteractionManager } from "@reactive-agents/interaction"
import { EventBusLive } from "@reactive-agents/core"
const program = Effect.gen(function* () {
const interaction = yield* InteractionManager
yield* interaction.switchMode("agent-1", "supervised")
})
await Effect.runPromise(
program.pipe(
Effect.provide(createInteractionLayer()),
Effect.provide(EventBusLive),
),
)

Reach for InteractionManager first; it delegates to the other four services so you rarely need to depend on them individually.

MethodBacked byDoes
getMode(agentId) / switchMode(agentId, mode)ModeSwitcherRead/set the active interaction mode
evaluateTransition(agentId, context)ModeSwitcherCheck the configured transition/escalation rules against run context
notify(params) / listUnread() / markRead(id)NotificationServiceSend and track notifications across channels
createCheckpoint(params) / resolveCheckpoint(id, status, comment?) / listPendingCheckpoints(agentId)CheckpointServicePause at a milestone, resolve it with a human decision
startCollaboration(params) / endCollaboration(id) / sendCollaborationMessage(params)CollaborationServiceReal-time back-and-forth session between agent and user
getPreference(userId) / shouldAutoApprove(params)PreferenceLearnerRead a learned approval pattern; decide whether to skip a prompt
approvalGate(action, timeoutMs?)InteractionManagerSuspends the calling fiber, publishes an approval-requested event carrying a generated gate id, and resolves to an ApprovalResult once something calls resolveApproval with that id (or the timeout elapses)
resolveApproval(gateId, approved, reason?)InteractionManagerCalled from elsewhere (a UI, a CLI prompt, a webhook) with the gate id read off the approval-requested event, to unblock the waiting approvalGate call
import { Effect } from "effect"
import { InteractionManager } from "@reactive-agents/interaction"
// The agent-side fiber: suspends until resolved or timed out.
const requestDeletion = Effect.gen(function* () {
const interaction = yield* InteractionManager
const result = yield* interaction.approvalGate("delete-production-file", 30_000)
return result.approved // false on denial or timeout; check result.timedOut / result.reason
})
// Elsewhere — a handler subscribed to the "approval-requested" EventBus event,
// reading { gateId, action } off its payload:
const respondToApproval = (gateId: string) =>
Effect.gen(function* () {
const interaction = yield* InteractionManager
yield* interaction.resolveApproval(gateId, true, "confirmed by reviewer")
})

PreferenceLearner observes approval/denial history per user (ApprovalPattern) and shouldAutoApprove uses it to skip a prompt once a pattern is confident enough, tuned by InterruptionTolerance. This is a local, in-process heuristic — not the same mechanism as the reactive-intelligence calibration store.