Help us shape the future of Go! Take the 2026 Go Developer Survey

einorun

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: MIT Imports: 36 Imported by: 0

README

einorun

CI Go Reference

中文

einorun runs agents built on Eino as durable, resumable runs. Eino's ADK gives you the agent loop; einorun adds what a production host needs around it.

  • Durable input. A run claims input from a Feed and picks up messages that arrive while it works.
  • Checkpoints and recovery. The process is recorded in a Journal at safe points; a run resumes after a crash, or after waiting for an external result.
  • Tool calls handed over. Tools can hand a call to another system and wait (Await), carry on with a receipt (Detached), submit it for a human decision, or pause the run until a person approves, rejects or edits the call, then carry it out in the same turn.
  • Structured completion and output guards. End a run with a structured decision, check final text before it is delivered, share one correction budget.
  • Context management. Large results are offloaded, old tool calls cleared, long histories summarized.
  • Built-in extensions: a task list (Planning), delegation to sub-agents (Subagent) and skills (Skills).
  • A live stream of the run's process, and provider adapters for the major model vendors.

einorun knows nothing about your business. Your instructions, tools, approvals and executors plug in through tool specs, guards and extensions. Persistence is yours too: implement two small interfaces against your own schema, and check them with journaltest.

Requires Go 1.27+.

einorun is under active development. The design is in docs/design.md.

Packages

Package
einorun Run records and the Feed and Journal contracts
llm Model contract, single calls and structured output
provider Chat models, embeddings, rerank, model discovery and probes for major vendors
stream Live display stream of a run
memory Long-term memory: recall extension and extraction
toolname Valid, deterministic model-visible names for external tools
tools/web Web search and page reading tools over your own services
inmem In-memory Feed and Journal
journaltest Contract suites for your Feed and Journal

Example

examples/chat is a command-line agent in about 150 lines: an in-memory conversation, a provider model, a tool, the task list and sub-agents, with the reply streamed to the terminal.

EINORUN_BRAND=openai EINORUN_BASE_URL=https://api.openai.com/v1 \
  EINORUN_MODEL=gpt-4.1 EINORUN_API_KEY=... go run ./examples/chat

Structured output without a run

type Title struct {
	Title string `json:"title" jsonschema_description:"A short title"`
}

title, usage, err := llm.GenerateObject[Title](ctx, factory, llm.GenerateRequest{
	Instruction: "Give the conversation a title.",
	Input:       transcript,
	Language:    llm.English,
})

License

MIT

Documentation

Overview

Package einorun runs agents built on Eino as durable, resumable runs.

A run reads its input from a Feed, records its process in a Journal and can be resumed from its last checkpoint after a crash or after waiting for an external result. Hosts keep their business rules (instructions, tools, approvals, external executors) and plug them in through tool specs, guards and extensions; einorun owns the run's state machine.

See docs/design.md in the repository for the design and its invariants.

Index

Constants

View Source
const (
	ReasonCorrectionsExhausted = "corrections_exhausted"
	ReasonBudgetExhausted      = "budget_exhausted"
	ReasonGuardRejected        = "guard_rejected"
)

Reasons for fallback completions.

View Source
const (
	// DefaultSubagentTool is the default name of the delegation tool.
	DefaultSubagentTool = "agent"
	// DefaultSubagentName is the default name of the sub-agent type.
	DefaultSubagentName = "general"
)
View Source
const (
	// DefaultSkillTool is the default name of the skill tool.
	DefaultSkillTool = "skill"
)
View Source
const MainAgentID = "main"

MainAgentID is the AgentScope.ID of the main agent.

View Source
const OffloadReadTool = "read_offloaded_tool_result"

OffloadReadTool is the tool the model reads offloaded results with. It is registered in every run.

Variables

View Source
var ErrCallRejected = errors.New("einorun: call rejected")

ErrCallRejected is returned (wrapped) by SaveToolCall when the host refuses a submission for a business reason, such as nobody being able to decide on it. The runtime records the call as failed, gives the reason to the model and continues. Use RejectCall to build such an error.

View Source
var ErrEmptyResponse = errors.New("einorun: the model produced no response")

ErrEmptyResponse reports a turn that produced neither text nor a completion, even after the model call was retried.

View Source
var ErrGuardRejected = errors.New("einorun: the guard rejected the output")

ErrGuardRejected reports a run whose guard rejected the output when no correction was left and no fallback completion is configured.

PlanTools are the names of the task list tools, in registration order.

Functions

func AttachMedia

func AttachMedia(ctx context.Context, refs ...MediaRef) error

AttachMedia attaches media the host stores to the result of the executing call, in order. The references are saved with the call; the runtime reads the media back before the next model call and passes it to the model within the run's media budget. It fails outside a call.

func Await

func Await(payload json.RawMessage) error

Await hands the call to an external executor and makes the run wait for its result: the call becomes HandoverAwait and the run suspends after the current batch of calls, to be resumed once the host has recorded the result. Only calls for which CanSuspend is true may await; elsewhere the call fails.

func CanSuspend

func CanSuspend(ctx context.Context) bool

CanSuspend reports whether the executing call may return Await. Calls of sub-agents and calls under WithoutSuspend cannot.

func Complete

func Complete(value json.RawMessage, fixed bool) error

Complete is returned by completion tools to end the run with value. A fixed completion ends the run even when new input is pending; a non-fixed one is superseded by new input. Any other error from a completion tool goes to the model and uses one of the run's corrections.

func CountTokens

func CountTokens(_ context.Context, messages []*schema.AgenticMessage, tools []*schema.ToolInfo) (int64, error)

CountTokens estimates the tokens of a model context: one per CJK character and a quarter per other character, tool definitions as JSON, and 1280 per media item.

func Detached

func Detached(receipt string, payload json.RawMessage) error

Detached hands the call to an external executor and lets the run carry on: the model receives receipt as the result and the external executor advances the record. Sub-agents cannot detach calls.

func IsInput

func IsInput(message *schema.AgenticMessage) bool

IsInput reports whether message was made from claimed conversation input, as opposed to messages the runtime adds itself: tool results, media carriers, summaries, notices and corrections.

func OffloadedPath

func OffloadedPath(callID string) string

OffloadedPath returns the path under which the result of the call with the provider call ID is offloaded when it is too large.

func RejectCall

func RejectCall(reason string) error

RejectCall returns an error that makes the runtime fail the call with reason.

func WithoutSuspend

func WithoutSuspend(ctx context.Context) context.Context

WithoutSuspend returns a context in which the executing call cannot suspend the run, for tools that need to process a result themselves before handing it to the model.

Types

type AdaptPart added in v0.3.0

type AdaptPart struct {
	// Modality is the native modality, or nil for text.
	Modality *llm.Modality
	MIME     string
	URL      string
	Data     []byte
	Text     string
	// Kind labels the projection for notes and metering (ocr, transcript,
	// document); it does not change runtime branching.
	Kind string
}

AdaptPart is one piece of an adaptation: text (Modality nil) or a native block built from URL or bytes.

type AdaptPolicy added in v0.3.0

type AdaptPolicy struct {
	Accepted []llm.Modality
	MaxBytes int64
}

AdaptPolicy tells the adapter which modalities the model still accepts and the largest item the run will take.

type Adaptation added in v0.3.0

type Adaptation struct {
	Parts []AdaptPart
}

Adaptation is what the model should see instead of, or after failing, a native media block.

type AgentScope

type AgentScope struct {
	// Name is the agent's name.
	Name string
	// Main is true for the main agent and false for sub-agents.
	Main bool
	// ID identifies the agent within the run: MainAgentID for the main agent,
	// and for a sub-agent the record ID of the call it serves, which is the
	// ParentID of its calls. Parallel sub-agents of the same type have
	// different IDs.
	ID string
}

AgentScope identifies the agent a tool instance or middleware belongs to.

type Block

type Block struct {
	ID          string
	Position    int64
	ModelCallID string
	Kind        BlockKind
	Text        string
	// Call is the tool call of a KindToolCall block. Journals persist the call
	// itself through the Calls of a Step or SaveToolCall and keep only the link
	// from the block; Resume hands blocks back with their calls attached.
	Call *ToolCall
}

Block is one piece of the run's process in the order the model produced it: reasoning, text or a tool call.

type BlockKind

type BlockKind string

BlockKind is the kind of a content block.

const (
	// KindThinking is model reasoning.
	KindThinking BlockKind = "thinking"
	// KindContent is model text.
	KindContent BlockKind = "content"
	// KindToolCall is a tool call made by the main agent.
	KindToolCall BlockKind = "tool_call"
)

type BuiltinTool

type BuiltinTool struct {
	// Notes are added to every call record of the tool; they win over the
	// tool's own notes with the same key.
	Notes map[string]string
	// Policy, when set, decides per call, as ToolSpec.Policy does.
	Policy func(ctx context.Context, call CallView) (CallPolicy, error)
}

BuiltinTool adjusts a tool the runtime or a built-in extension adds.

type CallCompletion

type CallCompletion struct {
	Value json.RawMessage `json:"value"`
	Fixed bool            `json:"fixed"`
}

CallCompletion is the completion value a completion tool returned. It is a copy kept with the call; the active completion of a run lives only in the run's checkpoint.

type CallContext

type CallContext struct {
	// RecordID is the ID of the call record.
	RecordID string
	// ModelCallID is the model call that requested the call.
	ModelCallID string
	// ProviderCallID is the call identifier the model gave.
	ProviderCallID string
}

CallContext identifies the call a tool is executing.

func CallFrom

func CallFrom(ctx context.Context) (CallContext, bool)

CallFrom returns the call a tool is executing, and false outside a call.

type CallDecision added in v0.2.0

type CallDecision struct {
	// Approved runs the call; otherwise, including for the zero value, it is
	// rejected and the model sees Reason.
	Approved bool   `json:"approved"`
	Reason   string `json:"reason,omitempty"`
	// Arguments, when set on an approval, replace the arguments the model
	// gave; the spec's Policy does not check them again.
	Arguments string `json:"arguments,omitempty"`
}

CallDecision is the host's decision on a call paused for one (see CallPolicy.Confirm). The host writes it; the runtime carries it out when the run resumes.

type CallOutcome

type CallOutcome struct {
	Agent AgentScope
	// Name is the model-visible tool name.
	Name string
	// Call is the call record after the outcome was recorded.
	Call ToolCall
	// Raw is the result as the tool returned it, before context management
	// turned it into what the model sees; empty for failed calls and calls
	// waiting for an external result.
	Raw    string
	Origin Origin
}

CallOutcome is the outcome of one call as observers see it.

type CallPolicy

type CallPolicy struct {
	// Submit, when set, submits the call for a decision by the host instead
	// of executing it.
	Submit *Submission
	// Confirm, when set, pauses the run for a decision on the call before it
	// runs. Only main-agent calls that can suspend pause; elsewhere the call
	// fails. Submit and Confirm are exclusive.
	Confirm *Confirmation
	// Replayable and SideEffects, when set, override the spec's traits.
	Replayable  *bool
	SideEffects *bool
	// Notes are added to the call record.
	Notes map[string]string
}

CallPolicy is a policy's decision for one call.

type CallRejection

type CallRejection struct {
	Reason string
}

CallRejection is a rejected submission with a reason for the model.

func (*CallRejection) Error

func (e *CallRejection) Error() string

Error returns the reason.

func (*CallRejection) Is

func (e *CallRejection) Is(target error) bool

Is reports whether target is ErrCallRejected.

type CallStatus

type CallStatus string

CallStatus is the status of a tool call. The runtime only produces the statuses below; hosts may persist further statuses for calls they own, such as expired or cancelled submissions, and the runtime treats any status it does not know as settled. Hosts may also record a submission they reject as StatusRejected.

const (
	// StatusQueued is a call the model made that has not started.
	StatusQueued CallStatus = "queued"
	// StatusRunning is a call being executed.
	StatusRunning CallStatus = "running"
	// StatusWaiting is a call waiting for an external result.
	StatusWaiting CallStatus = "waiting"
	// StatusAwaitingDecision is a call submitted for a decision by the host,
	// or paused for one (see CallPolicy.Confirm).
	StatusAwaitingDecision CallStatus = "awaiting_decision"
	// StatusSucceeded is a call that returned a result.
	StatusSucceeded CallStatus = "succeeded"
	// StatusFailed is a call that returned an error, which the model saw.
	StatusFailed CallStatus = "failed"
	// StatusInterrupted is a call cut off before it finished whose outcome is
	// harmless to repeat or had no side effects.
	StatusInterrupted CallStatus = "interrupted"
	// StatusNeedsReview is a call cut off before it finished whose side effects
	// may or may not have happened.
	StatusNeedsReview CallStatus = "needs_review"
	// StatusRejected is a paused call the host rejected; the model saw the
	// reason.
	StatusRejected CallStatus = "rejected"
)

func (CallStatus) Settled

func (s CallStatus) Settled() bool

Settled reports whether the call has a final outcome. Statuses the runtime does not know are the host's own final statuses; the empty status is not a status at all and is not settled.

type CallView

type CallView struct {
	// Name is the model-visible tool name.
	Name      string
	Arguments string
	// CallID is the identifier the model gave.
	CallID string
	Agent  AgentScope
}

CallView describes a call to a policy.

type Changes

type Changes struct {
	// Blocks are new blocks and blocks whose position or text changed, in
	// position order.
	Blocks []Block
	// Calls are new and changed calls, including sub-agent calls.
	Calls []ToolCall
	// RemovedBlocks are the IDs of removed blocks.
	RemovedBlocks []string
	// RemovedCalls are the IDs of the calls of removed blocks.
	RemovedCalls []string
}

Changes are the changes to a run's process since the last successful save. Journals apply removals first, then calls, then blocks.

func (Changes) Empty

func (c Changes) Empty() bool

Empty reports whether there are no changes.

type Claim

type Claim struct {
	// Messages is the conversation up to EndSeq: a snapshot, not only the
	// messages that arrived since the last claim.
	Messages []Message
	// EndSeq is the boundary actually claimed. It may be lower than requested;
	// the input above it stays pending.
	EndSeq int64
}

Claim is the result of claiming input.

type ClaimObserver

type ClaimObserver interface {
	OnClaim(ctx context.Context, claim Claim)
}

ClaimObserver sees every claim of new input.

type Closer

type Closer interface {
	Close() error
}

Closer extensions are closed when Run returns.

type Completion

type Completion struct {
	Source CompletionSource `json:"source"`
	// CallID is the record ID of the completion call when Source is FromTool.
	CallID string          `json:"callId,omitempty"`
	Value  json.RawMessage `json:"value"`
	// Fixed completions are not superseded by new input.
	Fixed bool `json:"fixed"`
	// Reason is why a fallback completion was produced.
	Reason string `json:"reason,omitempty"`
}

Completion is a structured result that ends a run.

type CompletionPolicy

type CompletionPolicy struct {
	// Fallback produces the value of a fixed completion when the output is
	// still invalid and cannot be corrected any more. reason is one of
	// ReasonCorrectionsExhausted, ReasonBudgetExhausted and
	// ReasonGuardRejected.
	Fallback func(reason string) json.RawMessage
	// FinalNotice, when set, replaces the note the runtime adds when the
	// iteration budget is spent.
	FinalNotice string
}

CompletionPolicy configures how runs with completion tools end.

type CompletionSource

type CompletionSource string

CompletionSource is what produced a completion.

const (
	// FromTool is a completion returned by a completion tool.
	FromTool CompletionSource = "tool"
	// FromGuard is a completion a guard decided.
	FromGuard CompletionSource = "guard"
	// FromFallback is a completion the host's fallback produced.
	FromFallback CompletionSource = "fallback"
)

type Config

type Config struct {
	// Language selects the model-facing text the runtime writes. The language
	// of ADK's own prompts is a process-wide setting the host makes with
	// adk.SetLanguage.
	Language llm.Language
	// Text overrides the default model-facing text of Language, field by
	// field; empty fields keep the default.
	Text Text
}

Config configures a Runtime.

type Confirmation added in v0.2.0

type Confirmation struct {
	Payload json.RawMessage
}

Confirmation pauses a call for a decision by the host. The call is recorded with StatusAwaitingDecision and Payload, the run suspends after the current batch, and the host decides by writing the call's Decision (see Journal). When the run resumes, the runtime carries the decision out within the same turn: an approved call runs, with the decision's arguments when set, and a rejected call gives the model the reason.

type ContextPolicy

type ContextPolicy struct {
	// ResultPercent is the share of the context window a single tool result
	// may take before it is offloaded with a preview (default 10).
	ResultPercent int
	// MinOffloadBytes is the smallest offload threshold (default 4000).
	MinOffloadBytes int
	// ClearPercent is the share of the window at which older tool calls are
	// cleared (default 75).
	ClearPercent int
	// KeepRounds is how many recent tool rounds clearing keeps (default 2).
	KeepRounds int
	// SummaryPercent is the share of the window a summary may take, capped at
	// the model's output limit (default 10).
	SummaryPercent int
	// InstructionTokens is the estimate of the summary instruction (default
	// 2000).
	InstructionTokens int
	// TokenCounter replaces the default estimate.
	TokenCounter func(ctx context.Context, messages []*schema.AgenticMessage, tools []*schema.ToolInfo) (int64, error)
	// OmitManagementNote leaves the context-management note out of the
	// instruction.
	OmitManagementNote bool
}

ContextPolicy tunes context management. Zero fields take the defaults.

type ContextReserver

type ContextReserver interface {
	ReservedTokens(scope AgentScope) int
}

ContextReserver extensions add text to an agent's model calls outside the agent's state, such as a reminder added when the model is wrapped. Before each model call the runtime lowers the summary threshold of the agent by the tokens they report, so the call still fits the window.

type Extension

type Extension interface {
	Name() string
}

Extension adds behaviour to runs. An extension implements Name and any of the optional interfaces below; names must be unique within a run.

func Planning

func Planning() Extension

Planning returns the extension that gives the main agent a task list. The list is kept in the run's checkpoint and published as the run's plan (Step.Plan, Result.Plan and the stream). Tasks the framework removes once all of them are completed stay in the plan as completed.

func Skills

func Skills(spec SkillsSpec) Extension

Skills returns the extension that gives agents a tool to load skills. Skills that declare a forked context run in a sub-agent when the run also has the Subagent extension; otherwise, and inside sub-agents, they load in the current context. The skill tool's results are never offloaded or cleared and are kept verbatim by summaries. A skill's model and agent fields are not used: forked skills run in the run's sub-agent with the run's model, and fork_with_context runs as fork.

func Subagent

func Subagent(spec SubagentSpec) Extension

Subagent returns the extension that lets the main agent hand tasks to sub-agents. A sub-agent uses the main agent's tools except tools marked MainOnly, delegation and the task list, with the same model factory and its own middlewares; it shares extension instances, the media budget and the multimodal switch with the main agent. Its calls are recorded under the delegation call (ToolCall.ParentID) and reported in Result.Calls.

The delegation tool is replayable and has side effects when a tool the sub-agent can use has them. Skills that run in a forked context use the same sub-agent.

type Feed

type Feed interface {
	Watch(ctx context.Context) (signals <-chan struct{}, stop func(), err error)
	Pending(ctx context.Context, after int64) (int64, error)
	Claim(ctx context.Context, through int64) (Claim, error)
}

Feed is the durable input of a run. Input is numbered with increasing sequence numbers.

Contract:

  • Watch returns once the subscription is in effect. Signals only wake the runtime, which then calls Pending; signals may be coalesced or lost, and the runtime also polls.
  • Pending returns the highest sequence number above after that can be claimed now, or 0 when there is none.
  • Claim binds input up to through to the run and returns the conversation snapshot up to the boundary it claimed. Claiming is not consuming: the host consumes input when it delivers the run's result.
  • Claiming the same boundary again returns the same EndSeq as long as the input has not been consumed; the runtime relies on this to replay its last claim after a restart.
  • Claim fails when the snapshot is empty or the boundary is at or below the input already consumed. Claiming what Pending reported moves the claimed boundary forward; a claim that does not fails the run.

type Guard

type Guard interface {
	// Review is called for every candidate text, including candidates that
	// turn out to be superseded by new input. An error aborts the run.
	Review(ctx context.Context, turn TurnView) (Verdict, error)
}

Guard reviews candidate text before a run delivers it. A guard reviews direct text only, never completion results.

type Handover

type Handover string

Handover records who advances a call other than the runtime.

const (
	// HandoverNone is a call the runtime advances.
	HandoverNone Handover = ""
	// HandoverAwait is a call advanced outside the runtime while the run waits
	// for it: the run suspends after the current batch of calls.
	HandoverAwait Handover = "await"
	// HandoverDetached is a call advanced outside the runtime while the run
	// carries on with a receipt.
	HandoverDetached Handover = "detached"
	// HandoverSubmitted is a call submitted for a decision by the host; the run
	// carries on with a receipt.
	HandoverSubmitted Handover = "submitted"
)

type Instantiable

type Instantiable interface {
	Instance(ctx context.Context, run RunScope) (Extension, error)
}

Instantiable extensions create one instance per run. The instance is shared by the main agent and its sub-agents and must be safe for concurrent use. Other extensions are used as they are.

type InstructionProvider

type InstructionProvider interface {
	Instruction(scope AgentScope) string
}

InstructionProvider adds text to an agent's instruction.

type Journal

type Journal interface {
	SaveStep(ctx context.Context, step Step) error
	SaveToolCall(ctx context.Context, call ToolCall) error
}

Journal persists a run as it executes.

Contract:

  • Every call the runtime writes, through SaveToolCall or the Calls of a Step, is a complete snapshot of the record at its Rev: all fields, including every note. A higher Rev never carries less than a lower one.
  • SaveStep writes a step atomically. Changes are incremental; Usage, Plan, Completion and State are the run's current values and replace the stored ones (nil clears them). Steps are written one at a time; SaveToolCall may be called concurrently with each other and with SaveStep.
  • Calls are merged with MergeCall semantics. A Step may carry a call snapshot older than a SaveToolCall that already happened; it must not win. Blocks only link to their call; the call itself is written through Calls or SaveToolCall.
  • Writes the host makes outside the runtime (dispatching to an external executor, settling an external call, deciding a submission, deciding a paused call) are authoritative; OverlayExternal describes them.
  • SaveToolCall that submits a call for a decision (Handover HandoverSubmitted) is where the host creates the submission, in the same transaction. It returns an error wrapping ErrCallRejected to refuse it, and then must not have persisted the write. The same holds for a call the runtime pauses for a decision (Status StatusAwaitingDecision with HandoverNone, see CallPolicy.Confirm): its first write is where the host creates the pending decision, and refusing it fails the call. The host decides a paused call by writing its Decision; the run then resumes and carries the decision out. A decision is final once written: the host does not change it, and, as for any resume, runs one execution of a run at a time, so a decision is carried out once. A host that notifies reviewers of calls needing review does so when the merged record newly reaches StatusNeedsReview, not because the incoming snapshot says so.
  • Any other error aborts the run and is returned from Run.

The journaltest package checks these rules against an implementation.

type Limits

type Limits struct {
	// MaxIterations caps model calls per turn; zero or less means 20. A new
	// claim of input resets the count; a correction rerun keeps it.
	MaxIterations int
	// MaxTurns caps the turns of a run; zero means no limit.
	MaxTurns int
	// Corrections is how many corrections a run may use (batch violations,
	// completion tool errors, guard corrections); zero or less means 1.
	Corrections int
}

Limits bound a run.

type MediaAdapter added in v0.3.0

type MediaAdapter interface {
	Adapt(ctx context.Context, ref MediaRef, policy AdaptPolicy) (Adaptation, error)
}

MediaAdapter projects media the model cannot take natively into text or other accepted modalities. Hosts supply OCR, transcription and document conversion; nil on the request means no projection.

type MediaReader

type MediaReader func(ctx context.Context, ref MediaRef) ([]byte, error)

MediaReader reads media the host stores.

type MediaRef

type MediaRef struct {
	// Key identifies the media for the host. Hosts namespace keys so that
	// message attachments and tool media cannot collide.
	Key    string `json:"key"`
	MIME   string `json:"mime"`
	SHA256 string `json:"sha256,omitempty"`
	Size   int64  `json:"size"`
}

MediaRef refers to media the host stores. The runtime never stores media bytes in records; it reads them back through the host's media reader and checks SHA256 before handing them to a model.

type MediaURLFunc added in v0.3.0

type MediaURLFunc func(ctx context.Context, ref MediaRef) (string, error)

MediaURLFunc returns a stable URL the model provider can fetch for ref. Empty URL or an error falls back to ReadMedia and base64.

type MemoryJournal

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

MemoryJournal keeps a run's records in memory. It is the journal of runs without one; package inmem offers it for tests and examples.

func NewMemoryJournal

func NewMemoryJournal() *MemoryJournal

NewMemoryJournal returns an empty journal.

func (*MemoryJournal) Call

func (j *MemoryJournal) Call(id string) (ToolCall, bool)

Call returns the stored record of a call.

func (*MemoryJournal) External

func (j *MemoryJournal) External(_ context.Context, update ToolCall) error

External applies a write made outside the runtime, as a host does when it dispatches a call to an external executor or settles it, with OverlayExternal semantics.

func (*MemoryJournal) Load

func (j *MemoryJournal) Load(resume Resume)

Load replaces the journal's content with resume, as a host's journal would hold it after a restart.

func (*MemoryJournal) Resume

func (j *MemoryJournal) Resume() Resume

Resume returns the saved checkpoint and the latest records, ready to hand back to a run.

func (*MemoryJournal) SaveStep

func (j *MemoryJournal) SaveStep(_ context.Context, step Step) error

SaveStep applies a step.

func (*MemoryJournal) SaveToolCall

func (j *MemoryJournal) SaveToolCall(_ context.Context, call ToolCall) error

SaveToolCall merges one call.

func (*MemoryJournal) Usage

func (j *MemoryJournal) Usage() Usage

Usage returns the usage of the last saved step.

type Message

type Message struct {
	// ID and Revision identify the message content. The runtime adds a message
	// to the model history once per ID and Revision; a new revision of a
	// message enters the history again.
	ID       string
	Revision string
	Role     Role
	Content  string
	// Media is an attachment the runtime may pass to the model directly, read
	// lazily within the run's media budget.
	Media *MediaRef
	// Meta is passed to guards and extensions and never interpreted by the
	// runtime.
	Meta map[string]string
}

Message is one message of the conversation a run works on.

type Model

type Model struct {
	// New creates model components; see llm.ModelFactory.
	New llm.ModelFactory
	// ContextWindow is the model's context window in tokens; zero means
	// llm.DefaultContextWindow.
	ContextWindow int
	// MaxOutputTokens caps a single output; zero means no limit.
	MaxOutputTokens int
	// Inputs are the input modalities the model accepts besides text.
	Inputs []llm.Modality
	// ToolResultMedia is true when the model accepts media inside tool
	// results; otherwise media of tool results follows as a user message.
	ToolResultMedia bool
}

Model describes the chat model of a run.

type ModelMiddleware

type ModelMiddleware interface {
	ModelMiddlewares(scope AgentScope) []adk.TypedChatModelAgentMiddleware[*schema.AgenticMessage]
}

ModelMiddleware adds ADK middlewares to an agent, after the runtime's own (see the execution order in the design). They must not wrap tools; use ToolMiddleware for that.

type Origin

type Origin string

Origin is where a call outcome reported to observers comes from.

const (
	// OriginExecuted is a call the tool executed.
	OriginExecuted Origin = "executed"
	// OriginSubmitted is a call submitted for a decision; Result is the
	// receipt.
	OriginSubmitted Origin = "submitted"
	// OriginRestored is a result patched into the model context on recovery.
	OriginRestored Origin = "restored"
)

type OutputObserver

type OutputObserver interface {
	AfterModelOutput(ctx context.Context, scope AgentScope, output *schema.AgenticMessage)
}

OutputObserver sees every finalized model output before its tools run.

type PinProvider

type PinProvider interface {
	Pin(messages []*schema.AgenticMessage) map[string]bool
}

PinProvider names tool calls to keep verbatim when the context is summarized, by the call identifiers the model gave.

type PlanTask

type PlanTask = stream.PlanTask

PlanTask is one entry of the run's task list.

type Request

type Request struct {
	RunID string
	// Instruction is the system instruction of the main agent.
	Instruction string
	Model       Model
	Tools       []ToolSpec
	Feed        Feed
	// Journal persists the run; nil means an in-memory journal, and a
	// suspended run then returns Result.Resume.
	Journal Journal
	// Resume continues a run from its last checkpoint.
	Resume *Resume
	// ReadMedia reads the media of messages and tool results; nil means
	// media is only referred to in text unless MediaURL succeeds.
	ReadMedia MediaReader
	// MediaURL returns a fetchable URL for media; tried before ReadMedia
	// when sending native blocks to the model.
	MediaURL MediaURLFunc
	// AdaptMedia projects media the model cannot take natively; nil means
	// unsupported media becomes an unavailable note (tool path) or stays a
	// text link (user attachments).
	AdaptMedia MediaAdapter
	// Stream receives the run's display deltas, serially; it must not block.
	Stream func(stream.Delta)
	// StreamID identifies the stream of this execution attempt; empty means a
	// new random identifier.
	StreamID   string
	Limits     Limits
	Completion *CompletionPolicy
	// Guard reviews candidate text. It may be an extension instance
	// registered in Extensions, or an Instantiable extension's prototype, in
	// which case the run's instance is used.
	Guard      Guard
	Extensions []Extension
	// Context tunes context management.
	Context ContextPolicy
	// DiscardUndelivered drops direct text superseded by new input from the
	// model history; the process record keeps it.
	DiscardUndelivered bool
	// BuiltinTools adjusts the tools the runtime and the built-in extensions
	// add, such as the delegation tool, the task list tools, the skill tool
	// and OffloadReadTool, by model-visible name (including a custom ToolName).
	// Naming a tool the run does not add is an error; host tools carry these
	// settings in their ToolSpec. The skill and offload read tools are also
	// used by sub-agents; a policy tells agents apart by CallView.Agent.
	BuiltinTools map[string]BuiltinTool
}

Request is one run.

type RestoreObserver

type RestoreObserver interface {
	AfterRestore(ctx context.Context, view RestoreView) error
}

RestoreObserver sees the records a run resumes from, after extension state was restored and before the model context is patched.

type RestoreView

type RestoreView struct {
	Blocks []Block
	Calls  []ToolCall
}

RestoreView is what a run resumes from: the latest call records, after the runtime settled interrupted calls.

type Result

type Result struct {
	// Text is the delivered text; it may be empty when Completion is set.
	Text       string
	Completion *Completion
	// EndSeq is the input boundary the result answers.
	EndSeq    int64
	Usage     Usage
	Blocks    []Block
	Calls     []ToolCall // sub-agent calls
	Plan      []PlanTask
	Suspended bool
	// Resume continues a suspended run that used the in-memory journal.
	Resume *Resume
}

Result is the outcome of a run.

type Resume

type Resume struct {
	State      []byte
	Blocks     []Block
	Calls      []ToolCall // sub-agent calls
	Plan       []PlanTask
	Completion *Completion
}

Resume is what a host hands back to continue a run: the last saved checkpoint and the latest records.

Blocks and Calls must reflect the host's latest records, including writes made outside the runtime. A host that dispatched a call to an external executor before the runtime recorded the handover projects that state onto the call: Handover and, for detached calls, the receipt in Result.

type Retain

type Retain int

Retain controls how context management treats a tool's results.

const (
	// RetainDefault results are offloaded when large and cleared when old.
	RetainDefault Retain = iota
	// RetainKeep results are offloaded when large but never cleared.
	RetainKeep
	// RetainIntact results are never offloaded or cleared.
	RetainIntact
)

type Role

type Role string

Role is the role of an input message.

const (
	// RoleUser is input from the user side of the conversation.
	RoleUser Role = "user"
	// RoleAssistant is a reply already delivered on the assistant side.
	RoleAssistant Role = "assistant"
)

type RunScope

type RunScope struct {
	RunID    string
	Language llm.Language
	// Model is the run's model factory, for extensions that call the model
	// themselves; they report the usage through UsageReporter.
	Model llm.ModelFactory
}

RunScope describes the run an extension instance serves.

type Runtime

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

Runtime executes runs. It is safe for concurrent use.

func New

func New(config Config) *Runtime

New returns a runtime.

func (*Runtime) InterruptedOutcome

func (r *Runtime) InterruptedOutcome(replayable, sideEffects bool) (CallStatus, string)

InterruptedOutcome returns the status and model-visible result the runtime gives a single call that started and did not finish, by its traits and with the runtime's text. Hosts use it to settle such calls outside a run, for example when an external executor is lost. Recovery also turns a call whose sub-agent calls have pending or unrepeatable effects into needs review; hosts leave such calls to the runtime.

func (*Runtime) Run

func (r *Runtime) Run(ctx context.Context, request Request) (Result, error)

Run executes a run until it completes, suspends or fails. See Result for what each outcome returns.

func (*Runtime) Text

func (r *Runtime) Text() Text

Text returns the model-facing text the runtime writes.

type SkillsSpec

type SkillsSpec struct {
	// Backend lists and loads the skills.
	Backend skill.Backend
	// ToolName is the name of the skill tool; DefaultSkillTool when empty.
	ToolName string
	// SystemPrompt renders the instruction added for skills.
	SystemPrompt skill.SystemPromptFunc
	// ToolDescription renders the skill tool's description.
	ToolDescription skill.ToolDescriptionFunc
	// ToolParams adjusts the skill tool's parameters.
	ToolParams func(ctx context.Context, defaults map[string]*schema.ParameterInfo) (map[string]*schema.ParameterInfo, error)
	// FormatReminder renders the reminder that lists the skills.
	FormatReminder func(ctx context.Context, in *skill.FormatReminderInput) (*skill.FormatReminderOutput, error)
	// BuildContent renders a loaded skill, for example with the list of its
	// resources.
	BuildContent func(ctx context.Context, loaded skill.Skill, rawArgs string) (string, error)
	// BuildForkMessages builds the input of a skill run by a sub-agent.
	BuildForkMessages func(ctx context.Context, in skill.TypedSubAgentInput[*schema.AgenticMessage]) ([]*schema.AgenticMessage, error)
	// FormatForkResult renders the result of a skill run by a sub-agent; by
	// default the sub-agent's last answer.
	FormatForkResult func(ctx context.Context, out skill.TypedSubAgentOutput[*schema.AgenticMessage]) (string, error)
}

SkillsSpec configures skills. Backend is required; the other fields are optional and passed to Eino's skill middleware as they are.

type Stage

type Stage int

Stage is where a tool middleware runs.

const (
	// StageOuter runs outside the runtime's recording, before a call is
	// recorded or submitted; every call of a batch passes through it. Use it
	// to schedule calls.
	StageOuter Stage = iota
	// StageInner runs around the actual execution of the tool.
	StageInner
)

type StagedToolMiddleware

type StagedToolMiddleware struct {
	Stage      Stage
	Middleware compose.ToolMiddleware
}

StagedToolMiddleware is a tool middleware and where it runs.

type Stateful

type Stateful interface {
	Save() (json.RawMessage, error)
	Restore(json.RawMessage) error
}

Stateful extensions keep state in the run's checkpoint.

type Step

type Step struct {
	Changes Changes
	Usage   Usage
	Plan    []PlanTask
	// Completion is the run's active completion, or nil when there is none.
	Completion *Completion
	// State is the opaque checkpoint the runtime resumes from.
	State []byte
}

Step is what the runtime saves at a safe point: the process changes since the last successful save, and the run's current usage, plan, active completion and checkpoint, which replace the stored values.

type SubagentSpec

type SubagentSpec struct {
	// ToolName is the name of the delegation tool; DefaultSubagentTool when
	// empty.
	ToolName string
	// Name is the sub-agent type the model selects; DefaultSubagentName when
	// empty.
	Name string
	// Description tells the main agent what the sub-agent is for; a general
	// description in the run's language when empty.
	Description string
	// Instruction is the sub-agent's instruction.
	Instruction string
	// MaxIterations is the iteration budget of one delegation; the run's
	// budget when zero.
	MaxIterations int
}

SubagentSpec configures delegation to sub-agents.

type Submission

type Submission struct {
	Receipt string
	Payload json.RawMessage
}

Submission is a call submitted for a decision. The host creates the submission when the runtime saves the call (see Journal); the model receives Receipt as the call's result.

type Text

type Text struct {
	// Cancelled is the result of a call that never got one because other
	// input arrived first. %[1]s is the tool name, %[2]s the call identifier.
	Cancelled string
	// InterruptedReplayable is the result of an interrupted call that may be
	// repeated.
	InterruptedReplayable string
	// Interrupted is the result of an interrupted call without side effects.
	Interrupted string
	// NeedsReview is the result of an interrupted call whose side effects are
	// unknown.
	NeedsReview string
	// CannotAwait fails a call that tried to wait for an external result where
	// the run cannot suspend.
	CannotAwait string
	// CannotDetach fails a call a sub-agent tried to hand over.
	CannotDetach string
	// CannotComplete fails a completion result from a tool that is not a
	// completion tool, or from a sub-agent.
	CannotComplete string
	// AwaitingResult is the placeholder result of a call waiting for an
	// external result.
	AwaitingResult string
	// CannotConfirm fails a call a policy pauses for a decision where it
	// cannot pause: in a sub-agent, for a completion tool, or for a tool the
	// runtime cannot carry out after the decision.
	CannotConfirm string
	// CallRejected is the result of a paused call the host rejected. %s is
	// the reason.
	CallRejected string
	// CallEdited precedes the result of a paused call approved with changed
	// arguments. %s is the arguments it ran with.
	CallEdited string
	// BatchTooMany rejects a batch with several completion tools. %s lists
	// the completion tools.
	BatchTooMany string
	// BatchMixed rejects a batch mixing a completion tool with other tools.
	// %s lists the completion tools.
	BatchMixed string
	// FinalNotice tells the model the iteration budget is spent.
	FinalNotice string
	// FinalNoticeCompletion does the same when completion tools remain. %s
	// lists them.
	FinalNoticeCompletion string
	// MediaUnavailable replaces media the model cannot view. %s is the media
	// type.
	MediaUnavailable string
	// MediaChanged replaces media whose content changed since the tool read
	// it. %s is the media key.
	MediaChanged string
	// MediaOverBudget replaces media beyond the run's media budget. %s is the
	// media key.
	MediaOverBudget string
	// ListSeparator joins tool names.
	ListSeparator string
	// SummaryPreamble introduces a summary of earlier context.
	SummaryPreamble string
	// OffloadRead describes the tool that reads offloaded results.
	OffloadRead string
	// SubagentDescription describes the general sub-agent.
	SubagentDescription string
	// SubagentTool describes the delegation tool.
	SubagentTool string
	// SubagentGuide is added to the main agent's instruction when it can
	// delegate. %s is the delegation tool name.
	SubagentGuide string
	// SubagentTypes introduces the list of sub-agents.
	SubagentTypes string
	// SubagentNoResult is the result of a delegation whose sub-agent gave no
	// answer.
	SubagentNoResult string
	// SkillForkResult wraps the answer of a skill run by a sub-agent. %[1]s
	// is the skill name, %[2]s the answer.
	SkillForkResult string
}

Text is the model-facing text the runtime writes. Config.Text overrides the default text of the run's language field by field: empty fields keep the default. Format verbs are documented per field and must be kept; a missing or wrong verb shows in the text the model sees. The memory and web tool packages take their text through their own options; structured output retries follow the language of the request.

func DefaultText

func DefaultText(language llm.Language) Text

DefaultText returns the default text for language, English for languages without their own.

type ToolCall

type ToolCall struct {
	// ID is the record ID the runtime assigns.
	ID string
	// ParentID is the record ID of the delegation call a sub-agent call
	// belongs to.
	ParentID string
	// ModelCallID is the model call that requested the call; sub-agent calls
	// carry the model call of their delegation call.
	ModelCallID string
	// CallID is the call identifier the model gave.
	CallID string
	// Name is the record name: the tool's original name for tools whose
	// model-visible name is derived, otherwise the model-visible name.
	Name      string
	Arguments string
	// Rev increases with every change the runtime makes to the record.
	Rev uint64
	// Result is the model-visible result, or the receipt of a call handed over.
	Result *string
	Error  *string
	// Media lists the media of the result in order.
	Media       []MediaRef
	Status      CallStatus
	StartedAt   *time.Time
	CompletedAt *time.Time
	// Replayable allows the model to call again when the outcome is unknown.
	Replayable bool
	// SideEffects marks calls that change state outside the run.
	SideEffects bool
	Handover    Handover
	// Payload is opaque data given when the call was handed over or
	// submitted; journals store it as is.
	Payload    json.RawMessage
	Completion *CallCompletion
	// Decision is the host's decision on a call paused for one; the host owns
	// it, and runtime snapshots never change or clear it.
	Decision *CallDecision
	// Notes are annotations by tool specs, guards and extensions. The runtime
	// only adds or changes notes, so every snapshot carries all of them; a
	// newer snapshot replaces the stored notes as a whole, so hosts keep data
	// of their own elsewhere.
	Notes map[string]string
}

ToolCall is the record of one tool call.

func MergeCall

func MergeCall(stored *ToolCall, incoming ToolCall) ToolCall

MergeCall returns the record that results from writing the runtime's snapshot incoming over stored, following the Journal contract. Journals that keep records as documents use it directly; SQL journals implement the same rules in their upsert.

  • A snapshot with a Rev not above the stored one changes nothing.
  • A newer snapshot replaces the descriptive fields (name, arguments, model call, traits) and the notes.
  • It replaces the outcome (status, result, error, media, times, completion, handover, payload) only while the stored call is neither settled nor handed over. Settled outcomes are final, whatever the newer status.
  • When the host recorded a handover first, settled or not, a newer snapshot that hands the call over too fills in the payload if there is none and the receipt while the call has neither a result nor an error. Status and times stay the host's.
  • The decision is the host's: a stored decision stays, and a snapshot's decision is taken only when none is stored.

func OverlayExternal

func OverlayExternal(stored ToolCall, update ToolCall) ToolCall

OverlayExternal returns stored with a write the host makes outside the runtime applied: Status, Result, Error, Media, CompletedAt, Handover, Payload and Decision come from update when set (a non-nil empty Media clears the media); Rev and every other field are kept. It describes the authoritative writes the Journal contract refers to.

func (ToolCall) Clone

func (c ToolCall) Clone() ToolCall

Clone returns a deep copy of c.

func (ToolCall) Validate

func (c ToolCall) Validate() error

Validate reports whether c can be written: it needs an ID and a status.

type ToolMiddleware

type ToolMiddleware interface {
	ToolMiddlewares(scope AgentScope) []StagedToolMiddleware
}

ToolMiddleware adds tool middlewares to an agent.

type ToolObserver

type ToolObserver interface {
	AfterTool(ctx context.Context, outcome CallOutcome)
}

ToolObserver sees every call outcome, with the raw result.

type ToolSpec

type ToolSpec struct {
	// Tool is an instance shared by the main agent and sub-agents. Exactly one
	// of Tool and New is set.
	Tool tool.BaseTool
	// New builds one instance per agent; the returned function, when not nil,
	// is called when that agent ends.
	New func(ctx context.Context, scope AgentScope) (tool.BaseTool, func(), error)
	// MainOnly registers the tool for the main agent only.
	MainOnly bool
	// RecordName returns the name recorded for a call, such as the original
	// name of a tool whose model-visible name is derived. Nil records the
	// model-visible name.
	RecordName func(arguments string) string
	// Replayable allows the model to call again when the outcome is unknown.
	// It does not make the runtime repeat calls.
	Replayable bool
	// SideEffects marks tools that change state outside the run.
	SideEffects bool
	// Policy decides per call, with the complete arguments, whether the call
	// is submitted for a decision instead of executed, and may adjust traits
	// and notes. An error fails the call and the model sees it.
	Policy func(ctx context.Context, call CallView) (CallPolicy, error)
	// Completion makes the tool a completion tool (see Complete).
	Completion bool
	// Retain controls context management of the tool's results.
	Retain Retain
	// PinInSummary keeps the tool's calls and results verbatim when the
	// context is summarized.
	PinInSummary bool
	// Notes are written to every call record of the tool.
	Notes map[string]string
}

ToolSpec registers a tool for a run.

type TurnView

type TurnView struct {
	// Claim is the snapshot claimed for this turn.
	Claim Claim
	// ModelInput is what the model saw when it produced Text, after all
	// rewrites and retries.
	ModelInput []*schema.AgenticMessage
	// Calls are this turn's calls of the main agent.
	Calls []CallOutcome
	Text  string
	// Superseded is true when new input is pending: the verdict is ignored,
	// notes still apply.
	Superseded bool
	// BudgetSpent is true when the text came at the end of the iteration
	// budget.
	BudgetSpent     bool
	CorrectionsLeft int
}

TurnView is what a guard reviews.

type Usage

type Usage = llm.Usage

Usage is the token usage of a run.

type UsageReporter

type UsageReporter interface {
	Usage() llm.Usage
}

UsageReporter extensions report the total usage of the model calls they made in this run, which the runtime adds to the run's usage. Only the usage since the run's latest start counts; usage from before a restart is already in the checkpoint.

type Verdict

type Verdict struct {
	Kind   VerdictKind
	Prompt string
	Value  json.RawMessage
	Fixed  bool
	// Notes are written to calls, keyed by call record ID.
	Notes map[string]map[string]string
}

Verdict is a guard's decision and the notes it writes.

type VerdictKind

type VerdictKind int

VerdictKind is a guard's decision.

const (
	// Accept delivers the text.
	Accept VerdictKind = iota
	// Correct reruns the turn with the rejected text and Prompt, using one
	// correction. Neither enters later history; the rerun keeps the remaining
	// iteration budget and is not a new turn. Without corrections left the
	// completion fallback applies.
	Correct
	// Finish ends the run with Value as a guard completion.
	Finish
)

Directories

Path Synopsis
examples
chat command
Command chat is a minimal command-line agent built with einorun: an in-memory conversation, a model from the provider package, a tool, the task list and sub-agents, with the reply streamed to the terminal.
Command chat is a minimal command-line agent built with einorun: an in-memory conversation, a model from the provider package, a tool, the task list and sub-agents, with the reply streamed to the terminal.
Package inmem provides in-memory implementations of einorun.Feed and einorun.Journal.
Package inmem provides in-memory implementations of einorun.Feed and einorun.Journal.
internal
checkpoint
Package checkpoint encodes model context into a stable JSON format that does not depend on how Eino serializes its types.
Package checkpoint encodes model context into a stable JSON format that does not depend on how Eino serializes its types.
prompt
Package prompt holds the model-facing text that einorun writes itself, in Chinese and English.
Package prompt holds the model-facing text that einorun writes itself, in Chinese and English.
Package journaltest checks implementations of einorun.Journal and einorun.Feed against their contracts.
Package journaltest checks implementations of einorun.Journal and einorun.Feed against their contracts.
Package llm holds the model contract shared by the runtime and the provider adapters, and single model calls that need no runtime: plain text generation and structured output.
Package llm holds the model contract shared by the runtime and the provider adapters, and single model calls that need no runtime: plain text generation and structured output.
Package memory gives runs long-term memory: Recall is an extension that picks the memories relevant to each claimed turn and shows them to the model, and Extract derives memory changes from a conversation.
Package memory gives runs long-term memory: Recall is an extension that picks the memories relevant to each claimed turn and shows them to the model, and Extract derives memory changes from a conversation.
Package provider creates Eino chat model components for the vendors listed in package vendor, with einorun's conventions applied: thinking switches, structured output, stop reasons and an HTTP transport suited to long model calls.
Package provider creates Eino chat model components for the vendors listed in package vendor, with einorun's conventions applied: thinking switches, structured output, stop reasons and an HTTP transport suited to long model calls.
apierr
Package apierr classifies failures of calls to model vendor APIs in a way that does not depend on the vendor.
Package apierr classifies failures of calls to model vendor APIs in a way that does not depend on the vendor.
discovery
Package discovery reads the models a vendor endpoint offers.
Package discovery reads the models a vendor endpoint offers.
embedding
Package embedding creates text embeddings through the OpenAI-compatible embeddings API.
Package embedding creates text embeddings through the OpenAI-compatible embeddings API.
internal/httpx
Package httpx sends JSON requests to vendor APIs and classifies failures with apierr.
Package httpx sends JSON requests to vendor APIs and classifies failures with apierr.
probe
Package probe checks that a model vendor endpoint is reachable and accepts the credentials, using a read-only request of each vendor.
Package probe checks that a model vendor endpoint is reachable and accepts the credentials, using a read-only request of each vendor.
rerank
Package rerank scores documents by their relevance to a query.
Package rerank scores documents by their relevance to a query.
vendor
Package vendor describes model vendors: how their endpoints are addressed and where they differ from the OpenAI-compatible conventions.
Package vendor describes model vendors: how their endpoints are addressed and where they differ from the OpenAI-compatible conventions.
Package stream defines the display projection of an agent run: snapshots, deltas and the operations that turn one into the next.
Package stream defines the display projection of an agent run: snapshots, deltas and the operations that turn one into the next.
Package toolname builds valid model-visible names for tools that come from other systems, such as MCP servers.
Package toolname builds valid model-visible names for tools that come from other systems, such as MCP servers.
tools
web
Package web provides optional web search and page reading tools.
Package web provides optional web search and page reading tools.

Jump to

Keyboard shortcuts

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