Documentation
¶
Overview ¶
Package httpsrv wires Poe HTTP requests into the router.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type CommandHandler ¶ added in v0.18.0
type CommandHandler interface {
HasPending(convID string) bool
Handle(ctx context.Context, convID, text string) (*command.Outcome, error)
// Passthrough reports whether text is an allowlisted agent command;
// if ok, rewritten is the prompt text to forward to the agent.
Passthrough(text string) (rewritten string, ok bool)
}
CommandHandler is the surface httpsrv depends on; *command.Broker implements it. Extracted so tests can inject handlers that return odd combinations the real one can't produce.
type Config ¶
type Config struct {
Router *router.Router
// Settings is the static response for `settings` requests. Parameter
// controls may be overridden per-request by ParameterControlsProvider.
Settings poeproto.SettingsResponse
// HeartbeatInterval is the SSE heartbeat tick. The heartbeat
// emits an animated `> _Thinking._` spinner via replace_response
// until the first user-visible write closes the gate. <=0 disables
// the heartbeat. Doubles as the spinner animation rate, so values
// in the 1–2s range read well to humans.
HeartbeatInterval time.Duration
// ParameterControlsProvider, if set, is called on each `settings`
// request to populate SettingsResponse.ParameterControls. If nil,
// Settings.ParameterControls is used as-is.
ParameterControlsProvider func() *poeproto.ParameterControls
// Commands, if set, intercepts relay chat-commands (login family,
// !help, !status, !models, !model, !new — any of the sigils /, !, .)
// and pasted redirect URLs from in-flight logins before they reach
// the router. Optional; nil disables the command surface.
Commands CommandHandler
// TurnTimeout is an OPTIONAL absolute wall-clock ceiling on a prompt
// turn run on a context DECOUPLED from the request ctx. Poe tears
// down the bot-facing HTTP connection pre-output on a transport drop;
// decoupling lets the in-flight turn finish so its answer can be
// buffered and served on the redrive, instead of aborting and losing
// the work.
//
// <=0 (the default) means NO absolute ceiling: a turn is bounded
// SOLELY by the progress-resetting IdleWriteTimeout backstop. While
// the agent keeps producing user-visible output the turn runs for as
// long as it needs — a long, actively-working turn is never cut. The
// absolute cap is opt-in for operators who deliberately want a hard
// upper bound regardless of progress; it is NOT a wedge guard (that
// is IdleWriteTimeout's job).
TurnTimeout time.Duration
// AnswerTTL bounds how long a buffered (absorbed) turn answer is held
// for a redrive before it is discarded. <=0 falls back to
// defaultAnswerTTL (2m).
AnswerTTL time.Duration
// IdleWriteTimeout is the per-stream backstop for a WEDGED turn: the
// agent has hung, no SSE content byte has been written, and the
// client never disconnected. If no user-visible chunk lands within
// this window the single wedged turn is cancelled so it cannot block
// a graceful drain forever; every other in-flight stream keeps
// draining. Heartbeat keepalive frames do NOT reset it — only real
// agent output does — so a genuinely wedged turn is detected even
// though its spinner keeps ticking. A tool_call session/update DOES
// reset it: a legitimately long-running tool is genuine progress, so
// it must not be cut. <=0 falls back to defaultIdleWriteTimeout (2m).
IdleWriteTimeout time.Duration
// StallThreshold is how long the SSE stream may go without a
// user-visible content write before the heartbeat re-arms the
// mid-turn keepalive spinner. Poe drops the bot-facing connection on
// content-starvation, so during a long tool-heavy turn (no tokens
// for minutes) the spinner must resume to keep the stream alive.
// It re-arms via `replace_response` (a content event that renders in
// place), preserving the text so far and animating a transient
// status line below it; the moment real output resumes the spinner
// is stripped. Before the first output there is no stall gate — the
// cold-start spinner fires immediately (see heartbeat). <=0 falls
// back to defaultStallThreshold (8s), conservatively under Poe's
// drop tolerance. Reuses HeartbeatInterval for the animation cadence.
StallThreshold time.Duration
// SSEWriteTimeout bounds every SSE wire write via a per-write
// connection deadline. A client that has stopped reading (Poe pressed
// Stop, or a dead transport) applies TCP backpressure; without a
// deadline a blocked write — including the terminal `done` — never
// returns and the turn never finalizes (the "Stop button stays"
// hang). With it, a wedged write fails after this window, the
// heartbeat swallows the error, and the terminal `done` still seals
// the stream so the HTTP response closes. <=0 falls back to
// defaultSSEWriteTimeout (30s): generous enough never to cut a
// slow-but-live reader mid-frame, tight enough to bound finalization.
SSEWriteTimeout time.Duration
}
Config configures a Handler.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler serves the /poe endpoint.
func New ¶
New creates a Handler. HeartbeatInterval <=0 disables heartbeat; otherwise no defaulting is applied — pass an explicit value. AnswerTTL and IdleWriteTimeout default when <=0 (see their docs). TurnTimeout is NOT defaulted: <=0 means no absolute turn ceiling, so the progress-resetting IdleWriteTimeout backstop is the sole guard.
Click to show internal directories.
Click to hide internal directories.