command

package
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 8, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package command implements the relay's chat-command surface: it brokers interactive OAuth login (bridging Poe turns into fir's _meta.auth.interactive two-call protocol) and the session-control commands (!status, !models, !model, !new, !help).

Each Poe conversation can have at most one in-flight login. The first login command (e.g. "!login anthropic") calls fir's authenticate to produce a URL; the next user turn from the same conversation submits the pasted redirect URL. The broker holds no goroutines — the actual blocking on the user input happens inside fir, parked across turns. The relay only remembers which conversation has a pending login for which method.

Commands accept the sigils "/", "!", and "." but user-facing prose suggests "!" (DisplaySigil): Poe's chat client intercepts "/"-prefixed messages as native slash commands and rejects unknown ones before they reach the bot, so "/login" is unreliable; "!"/"." pass straight through.

Index

Constants

View Source
const DisplaySigil = "!"

DisplaySigil is the command prefix shown in user-facing messages. It is deliberately not "/" so the suggested commands survive Poe's client-side slash-command interceptor.

Variables

This section is empty.

Functions

func IsCommand

func IsCommand(text string) bool

IsCommand reports whether text is any relay command the broker handles (the login family, "help", or a session command), under any accepted sigil. The HTTP handler uses this to decide whether to route a turn to the broker instead of forwarding it to the agent.

func IsLoginCommand

func IsLoginCommand(text string) bool

IsLoginCommand reports whether text is a login/logins/cancel-login command under any accepted sigil (/, !, .). Trims leading whitespace so users can paste the command after a thought.

Types

type Authenticator

type Authenticator interface {
	AuthMethods() []client.AuthMethod
	Authenticate(ctx context.Context, methodID, id, redirect string, cancel bool) (client.AuthResult, error)
}

Authenticator is the agent-side surface the broker depends on. The full *client.AgentProc satisfies it.

type Broker

type Broker struct {
	// contains filtered or unexported fields
}

Broker tracks per-conversation pending logins.

func New

func New(a Authenticator) *Broker

New constructs a Broker.

func (*Broker) Handle

func (b *Broker) Handle(ctx context.Context, convID, text string) (*Outcome, error)

Handle dispatches one user turn. Behaviour:

  1. If the conversation has a pending login, treat any non-command text as the pasted redirect URL.
  2. Otherwise interpret /login [provider], /logins, /cancel-login.

Returns (nil, nil) if the turn is not auth-related and should be forwarded to the normal prompt path.

func (*Broker) HasPending

func (b *Broker) HasPending(convID string) bool

HasPending reports whether the conversation is waiting for a pasted redirect URL.

func (*Broker) OfferLogin

func (b *Broker) OfferLogin() string

OfferLogin renders the onboarding message shown when the agent reports that no usable provider is connected (an "Authentication required" prompt error). It lists the loginable providers using the Poe-safe DisplaySigil. Safe for concurrent use. Returned text is empty-safe: it always yields actionable guidance, even with no OAuth methods.

func (*Broker) Passthrough

func (b *Broker) Passthrough(text string) (rewritten string, ok bool)

Passthrough decides whether text is an allowlisted agent command and, if so, returns the prompt text to forward to the agent (e.g. "!reload" → "/reload"). ok=false means the turn is not a passthrough command and should be handled normally. The command must be both allowlisted and actually advertised by the agent. Requires a wired Controller.

func (*Broker) SetController

func (b *Broker) SetController(c Controller)

SetController wires the session-control surface (the router) used by !status/!models/!model/!new. Call once at startup, after construction, to break the broker↔router construction cycle. Safe before any turns.

type Controller

type Controller interface {
	AvailableModels() (models []client.ModelInfo, currentID string)
	SetModelOverride(convID, modelID string) error
	ResetSession(convID string) error
	StatusFor(convID string) router.SessionStatus
	AgentCommands() []client.CommandInfo
	RelayInfo(convID string) router.RelayInfo
}

Controller is the per-conversation session-control surface used by the non-auth commands (!status, !models, !model, !new). *router.Router satisfies it. Optional: if nil, those commands report unavailable. (router never imports command — the dependency edge is one-way: command → router.)

type Outcome

type Outcome struct {
	// Text is a plain message to stream as a Poe `text` event.
	Text string
	// URL, if non-empty, is the auth URL to surface to the user. Text
	// may also be set with prose preceding/following the URL.
	URL string
	// Instructions accompany URL.
	Instructions string
}

Outcome is what the HTTP handler should render to the user. Exactly one of Text / URL / Error is set; Done is always implied (the auth turn never streams further chunks).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL