Documentation
¶
Overview ¶
Package orchestrator provides an agent.Router implementation that manages NPC agents within a Glyphoxa session. It adds address detection, cross-NPC awareness, and DM override capabilities on top of the base agent.Router contract.
Index ¶
- Variables
- type AddressDetector
- type BufferEntry
- type Option
- type Orchestrator
- func (o *Orchestrator) ActiveAgents() []agent.NPCAgent
- func (o *Orchestrator) AddAgent(a agent.NPCAgent) error
- func (o *Orchestrator) AgentByName(name string) agent.NPCAgent
- func (o *Orchestrator) BroadcastScene(ctx context.Context, scene agent.SceneContext) error
- func (o *Orchestrator) IsMuted(id string) (bool, error)
- func (o *Orchestrator) MuteAgent(id string) error
- func (o *Orchestrator) MuteAll() int
- func (o *Orchestrator) RemoveAgent(id string) error
- func (o *Orchestrator) Route(ctx context.Context, speaker string, transcript stt.Transcript) (agent.NPCAgent, error)
- func (o *Orchestrator) SetPuppet(speaker string, npcID string) error
- func (o *Orchestrator) UnmuteAgent(id string) error
- func (o *Orchestrator) UnmuteAll() int
- type UtteranceBuffer
Constants ¶
This section is empty.
Variables ¶
var ErrNoTarget = errors.New("orchestrator: no target NPC identified")
ErrNoTarget is returned when address detection cannot determine which NPC was addressed by a player's utterance.
Functions ¶
This section is empty.
Types ¶
type AddressDetector ¶
type AddressDetector struct {
// contains filtered or unexported fields
}
AddressDetector determines which NPC was spoken to by scanning the transcript text for NPC names, falling back through a priority chain of heuristics (DM override → last-speaker continuation → single-NPC fallback).
func NewAddressDetector ¶
func NewAddressDetector(agents []agent.NPCAgent) *AddressDetector
NewAddressDetector builds a name index from the given agents.
The index includes the full lowercase name of each NPC and every individual word of length ≥ 3 from that name. For example, "Grimjaw the Blacksmith" produces entries for "grimjaw the blacksmith", "grimjaw", and "blacksmith" (the word "the" is too short).
func (*AddressDetector) Detect ¶
func (d *AddressDetector) Detect( text string, lastSpeaker string, activeAgents map[string]*agentEntry, dmOverrides map[string]string, speaker string, ) (string, error)
Detect returns the agent ID of the NPC addressed in the transcript.
The detection strategy is applied in order:
- Explicit name match — scan text for indexed NPC names/fragments.
- DM override — if speaker has an active puppet override in dmOverrides.
- Last-speaker continuation — route to lastSpeaker if set and active.
- Single-NPC fallback — if exactly one unmuted NPC exists, route there.
- No match — return ("", ErrNoTarget).
func (*AddressDetector) Rebuild ¶
func (d *AddressDetector) Rebuild(agents []agent.NPCAgent)
Rebuild rebuilds the name index from a fresh set of agents. Call this after adding or removing agents.
type BufferEntry ¶
type BufferEntry struct {
// SpeakerID identifies the speaker (player user-ID or NPC agent ID).
SpeakerID string
// SpeakerName is the human-readable name of the speaker.
SpeakerName string
// Text is the utterance text.
Text string
// NPCID is non-empty when the utterance was produced by an NPC agent.
NPCID string
// Timestamp records when the utterance occurred.
Timestamp time.Time
}
BufferEntry represents a single utterance stored in the UtteranceBuffer.
type Option ¶
type Option func(*Orchestrator)
Option configures an Orchestrator during construction.
func WithBufferDuration ¶
WithBufferDuration sets the maximum age of entries in the cross-NPC utterance buffer. The default is 5 minutes.
func WithBufferSize ¶
WithBufferSize sets the maximum number of entries retained in the cross-NPC utterance buffer. The default is 20.
type Orchestrator ¶
type Orchestrator struct {
// contains filtered or unexported fields
}
Orchestrator manages NPC agents within a Glyphoxa session. It implements agent.Router and adds lifecycle management, address detection, cross-NPC awareness, and DM override capabilities.
All exported methods are safe for concurrent use.
func New ¶
func New(agents []agent.NPCAgent, opts ...Option) *Orchestrator
New creates an Orchestrator with the given NPC agents and functional options.
Each agent must have a unique agent.NPCAgent.ID; duplicates are silently dropped (last one wins). Passing a nil or empty agents slice is valid and results in an orchestrator with no active agents.
func (*Orchestrator) ActiveAgents ¶
func (o *Orchestrator) ActiveAgents() []agent.NPCAgent
ActiveAgents returns a snapshot of all NPC agents currently managed by this orchestrator, including both muted and unmuted agents.
func (*Orchestrator) AddAgent ¶
func (o *Orchestrator) AddAgent(a agent.NPCAgent) error
AddAgent registers a new NPC agent with the orchestrator. Returns an error if an agent with the same ID is already registered.
func (*Orchestrator) AgentByName ¶ added in v0.0.3
func (o *Orchestrator) AgentByName(name string) agent.NPCAgent
AgentByName returns the first agent whose Name() matches name (case-insensitive). Returns nil if no match is found.
func (*Orchestrator) BroadcastScene ¶
func (o *Orchestrator) BroadcastScene(ctx context.Context, scene agent.SceneContext) error
BroadcastScene pushes a scene update to all active (unmuted) agents. Errors from individual agents are collected; all agents are attempted regardless of individual failures. If multiple agents fail, the returned error is a joined error containing one wrapped error per failing agent.
func (*Orchestrator) IsMuted ¶ added in v0.0.3
func (o *Orchestrator) IsMuted(id string) (bool, error)
IsMuted reports whether the agent with the given ID is muted. Returns an error if id does not correspond to a registered agent.
func (*Orchestrator) MuteAgent ¶
func (o *Orchestrator) MuteAgent(id string) error
MuteAgent prevents the agent identified by id from receiving new utterances. Returns an error if id does not correspond to a registered agent.
func (*Orchestrator) MuteAll ¶ added in v0.0.3
func (o *Orchestrator) MuteAll() int
MuteAll mutes all agents atomically and returns the number of agents whose mute state was changed (agents already muted are not counted).
func (*Orchestrator) RemoveAgent ¶
func (o *Orchestrator) RemoveAgent(id string) error
RemoveAgent unregisters an NPC agent. Returns an error if not found.
func (*Orchestrator) Route ¶
func (o *Orchestrator) Route(ctx context.Context, speaker string, transcript stt.Transcript) (agent.NPCAgent, error)
Route determines which agent.NPCAgent was addressed by speaker's utterance and returns that agent. Before returning, Route injects recent cross-NPC utterances into the target agent's engine via engine.VoiceEngine.InjectContext.
If no NPC can be identified or the identified NPC is muted, Route returns ErrNoTarget.
func (*Orchestrator) SetPuppet ¶
func (o *Orchestrator) SetPuppet(speaker string, npcID string) error
SetPuppet forces all utterances from speaker to be routed to the NPC identified by npcID, bypassing address detection. Use for DM puppeteering.
Pass an empty npcID to clear the override for that speaker. Returns an error if npcID is non-empty and does not correspond to a registered agent.
func (*Orchestrator) UnmuteAgent ¶
func (o *Orchestrator) UnmuteAgent(id string) error
UnmuteAgent re-enables routing to the agent identified by id. Returns an error if id does not correspond to a registered agent. Calling UnmuteAgent on an already-unmuted agent is a no-op.
func (*Orchestrator) UnmuteAll ¶ added in v0.0.3
func (o *Orchestrator) UnmuteAll() int
UnmuteAll unmutes all agents atomically and returns the number of agents whose mute state was changed (agents already unmuted are not counted).
type UtteranceBuffer ¶
type UtteranceBuffer struct {
// contains filtered or unexported fields
}
UtteranceBuffer maintains a shared buffer of recent utterances from all NPCs and players. Each NPC can read from this buffer to understand what other NPCs have said recently (cross-NPC awareness).
The buffer enforces both a maximum entry count and a maximum age. Entries that exceed either limit are evicted automatically on every [Add] call.
All methods are safe for concurrent use.
func NewUtteranceBuffer ¶
func NewUtteranceBuffer(maxSize int, maxAge time.Duration) *UtteranceBuffer
NewUtteranceBuffer creates a buffer that retains at most maxSize entries and evicts entries older than maxAge.
func (*UtteranceBuffer) Add ¶
func (b *UtteranceBuffer) Add(entry BufferEntry)
Add appends an entry to the buffer and evicts entries that exceed the configured maximum size or age.
func (*UtteranceBuffer) Entries ¶
func (b *UtteranceBuffer) Entries() []BufferEntry
Entries returns all current buffer entries in chronological order. Intended for testing and debugging.
func (*UtteranceBuffer) Recent ¶
func (b *UtteranceBuffer) Recent(excludeNPCID string, maxEntries int) []BufferEntry
Recent returns up to maxEntries entries that are within the configured maxAge window, excluding any entries whose NPCID matches excludeNPCID. This allows an NPC to see what other NPCs and players have said without seeing its own utterances as "cross-NPC" context.
Entries are returned in chronological order (oldest first).