Documentation
¶
Overview ¶
Package external defines the neutral port between the agent application layer and out-of-process runtimes: Codex, Claude Code, and ACP agents.
A Driver owns one runtime type end to end: process lifecycle inside the bot workspace, the native wire protocol, and the translation of runtime events into the shared event.StreamEvent vocabulary. The application layer stays runtime-agnostic: it resolves a Driver from the session's runtime type, hands it a PromptInput, and persists the PromptResult — the same shape for every driver. New runtimes must implement Driver instead of growing new special cases in the application layer.
Index ¶
- Constants
- Variables
- func ApprovalCard(req approval.Request) event.StreamEvent
- func As[T any](r *Registry, runtimeType string) (T, bool)
- func AskUser(ctx context.Context, service userinput.FlowService, input PromptInput, ...) (userinput.Request, error)
- func ContainerWorkspace(ctx context.Context, workspaces Workspaces, botID, runtime string) (bridge.WorkspaceInfo, error)
- func CredentialError(err error) error
- func DecideApproval(ctx context.Context, service approval.FlowService, waiter func(string) func(), ...) approval.FlowResult
- func Fail(kind FailureKind, err error) error
- func FirstNonEmpty(values ...string) string
- func IsFailure(err error) bool
- func IsFailureKind(err error, kind FailureKind) bool
- func LimitStreamEvent(ev event.StreamEvent, limit contextlimit.ToolOutputLimit) event.StreamEvent
- func MetadataString(metadata map[string]any, key string) string
- func PublicMessage(message string) string
- func PumpSteering(ctx context.Context, source Steering, done, ready <-chan struct{}, ...) func()
- func Reported(kind FailureKind, message string, attrs ...slog.Attr) error
- func RequireContainerWorkspace(info bridge.WorkspaceInfo, runtime string) error
- func SelectedPermissionMode(runtimeMetadata, agentMetadata map[string]any, defaultMode string) string
- func TranscriptFromEvents(events []event.StreamEvent, fallbackText string) []sdk.Message
- func Upstream(err error) error
- func UserInputCard(req userinput.Request) event.StreamEvent
- type Account
- type AccountReader
- type ApprovalCall
- type BotAgentAuthPurger
- type Caps
- type Command
- type CommandKind
- type CommandProvider
- type CommandResult
- type CompactionResult
- type Compactor
- type ControlCapabilities
- type Controls
- type DependencyMissingError
- type DeviceLoginProvider
- type DeviceLoginStart
- type DeviceLoginStatus
- type Driver
- type EventSink
- type EventSinkFunc
- type Failure
- type FailureKind
- type Goal
- type GoalProvider
- type Image
- type Launcher
- type LauncherResolver
- type LauncherSource
- type Mode
- type ModeProvider
- type ModeState
- type ModelCatalog
- type ModelCatalogProvider
- type ModelCatalogRequest
- type ModelOption
- type PlanModeProvider
- type PromptInput
- type PromptResult
- type Question
- type Quota
- type QuotaReader
- type QuotaWindow
- type ReasoningEffortOption
- type Registry
- type SteerInput
- type Steering
- type ThreadForker
- type TranscriptRecorder
- type TurnStream
- func (s *TurnStream) EmitStreamEvent(ev event.StreamEvent)
- func (s *TurnStream) Finish()
- func (s *TurnStream) RecordTerminalDecision(ev event.StreamEvent)
- func (s *TurnStream) SteerInput(id, text string, accepted func())
- func (s *TurnStream) SteerInputIDs() []string
- func (s *TurnStream) Transcript(finalText string) []sdk.Message
- type VersionObserver
- type Workspaces
Constants ¶
const ( CommandTurn = turn.RuntimeCommandTurn CommandRead = turn.RuntimeCommandRead CommandOperation = turn.RuntimeCommandOperation )
const ( DeviceLoginPending = "pending" DeviceLoginSuccess = "success" DeviceLoginError = "error" DeviceLoginUnknown = "unknown" )
Device-code sign-in states. Unknown: the login is not tracked, e.g. the agent process restarted.
Variables ¶
var ( ErrControlUnsupported = errors.New("runtime control is unsupported") )
var CodexFormMarkers = userinput.ElicitationExtension{ CustomAnswer: func(meta map[string]any) (string, bool, error) { codex, ok := meta["codex"].(map[string]any) if !ok { return "", false, nil } other, exists := codex["isOtherAnswer"] if !exists { return "", false, nil } isOther, ok := other.(bool) if !ok { return "", false, errors.New("codex isOtherAnswer metadata must be a boolean") } if !isOther { return "", false, nil } target, err := userinput.RequiredMetaString(codex, "questionId", "codex custom-answer metadata") return target, true, err }, Secret: func(meta map[string]any) bool { codex, _ := meta["codex"].(map[string]any) secret, _ := codex["isSecret"].(bool) return secret }, }
CodexFormMarkers reads the markers Codex puts in a form property's _meta: the free-text "other" answer of a question, and secret input. They are Codex's wire convention, sent alike by its app-server and by codex-acp, which runs as a generic ACP agent; the Codex driver and the ACP client both read forms with them.
var ErrContainerWorkspaceRequired = errors.New("direct agent runtime requires a container workspace")
ErrContainerWorkspaceRequired reports a direct runtime asked to start in a workspace that is not a container.
var ErrDependencyMissing = errors.New("workspace dependency is not installed")
ErrDependencyMissing is the errors.Is target for DependencyMissingError.
ErrQuotaUnavailable: the runtime could not read the account's usage.
Functions ¶
func ApprovalCard ¶ added in v1.0.0
func ApprovalCard(req approval.Request) event.StreamEvent
ApprovalCard is the stream event that shows an approval to the user.
func As ¶ added in v1.0.0
As returns the runtime's implementation of a capability interface, false when the runtime does not declare it.
func AskUser ¶ added in v1.0.0
func AskUser(ctx context.Context, service userinput.FlowService, input PromptInput, question Question, emit func(event.StreamEvent), logger *slog.Logger) (userinput.Request, error)
AskUser puts a runtime's question to the user and waits for the answer.
func ContainerWorkspace ¶ added in v1.0.0
func ContainerWorkspace(ctx context.Context, workspaces Workspaces, botID, runtime string) (bridge.WorkspaceInfo, error)
ContainerWorkspace returns the bot's workspace, refusing one that is not a container: a runtime's process environment and paths assume that layout. A workspace that cannot be looked up is the runtime being unavailable.
func CredentialError ¶
CredentialError reports an Agent credential the user must fix (missing, of the wrong kind, revoked, or undecryptable) as a FailureCredential. Any other error is returned unchanged.
func DecideApproval ¶ added in v1.0.0
func DecideApproval(ctx context.Context, service approval.FlowService, waiter func(string) func(), input PromptInput, call ApprovalCall, emit func(event.StreamEvent), logger *slog.Logger) approval.FlowResult
DecideApproval forwards a runtime's own permission question to the user. The runtime's permission mode is the only policy layer for its native tools; Memoh's rules govern Memoh's tools, which the gateway enforces. A failure fails closed, as cancelled.
func Fail ¶ added in v0.21.0
func Fail(kind FailureKind, err error) error
Fail reports a failure of kind, caused by err when err is not nil.
func FirstNonEmpty ¶ added in v1.0.0
FirstNonEmpty returns the first value that is not blank, trimmed.
func IsFailureKind ¶ added in v1.0.0
func IsFailureKind(err error, kind FailureKind) bool
IsFailureKind reports whether err carries a Failure of kind.
func LimitStreamEvent ¶
func LimitStreamEvent(ev event.StreamEvent, limit contextlimit.ToolOutputLimit) event.StreamEvent
LimitStreamEvent bounds tool output before it enters a runtime transcript.
func MetadataString ¶ added in v1.0.0
MetadataString reads a trimmed string from metadata; anything else is empty.
func PublicMessage ¶ added in v1.0.0
PublicMessage makes what an agent said fit to show and keep: URLs lose their credentials and queries, and a whole response body is cut short.
func PumpSteering ¶ added in v1.0.0
func PumpSteering(ctx context.Context, source Steering, done, ready <-chan struct{}, supported func() bool, submit func(context.Context, SteerInput) error, onFailure func(error)) func()
PumpSteering delivers the run's steering queue to a running turn, in queue order, until the turn ends (done closes) or the returned stop is called; stop returns once the pump has, so an old pump cannot deliver an input to a later turn. ready, when set, holds the pump until the native turn can take input, and supported says whether it can at all. submit delivers one input and returns once the runtime consumed it. A failed delivery is never retried or moved to another turn: onFailure reports it and the pump stops.
func Reported ¶ added in v1.0.0
func Reported(kind FailureKind, message string, attrs ...slog.Attr) error
Reported is a failure the agent reported in its own words: kind is FailureReported, or FailureAuthRequired when the agent's protocol marked it as a sign-in problem. URLs in the message lose their credentials and queries. attrs describe the failure to the result record.
func RequireContainerWorkspace ¶
func RequireContainerWorkspace(info bridge.WorkspaceInfo, runtime string) error
RequireContainerWorkspace guards drivers whose executable environment and credential paths assume the container layout. The remote bridge maps file RPC paths, but it does not translate paths embedded in process environments.
func SelectedPermissionMode ¶ added in v1.0.0
func SelectedPermissionMode(runtimeMetadata, agentMetadata map[string]any, defaultMode string) string
SelectedPermissionMode is the conversation's permission mode: its own choice, else the Agent's, else the runtime's default.
func TranscriptFromEvents ¶
func TranscriptFromEvents(events []event.StreamEvent, fallbackText string) []sdk.Message
TranscriptFromEvents builds a transcript by folding a complete event sequence. Production uses the incremental builder wired into the prompt collector; this convenience exists for tests and offline tooling.
func Upstream ¶ added in v1.0.0
Upstream reports a failure that came from the agent or its process (a start that failed with its exit status and stderr, a refused resume, a control the agent rejected) in the words it failed with. A Failure, a missing workspace dependency, a workspace that is not a container and a cancellation pass through unchanged.
func UserInputCard ¶ added in v1.0.0
func UserInputCard(req userinput.Request) event.StreamEvent
UserInputCard is the stream event that puts a question to the user.
Types ¶
type Account ¶ added in v1.0.0
type Account struct {
SignedIn bool
// Email is empty when the runtime does not report one.
Email string
}
Account is the account an Agent's runtime is signed in to.
type AccountReader ¶ added in v1.0.0
type AccountReader interface {
Account(ctx context.Context, botID, botAgentID string) (Account, error)
}
AccountReader is implemented by runtimes that keep their own sign-in in the Agent's workspace, so only the runtime can say whether it is signed in.
type ApprovalCall ¶ added in v1.0.0
type ApprovalCall struct {
ToolCallID string
ToolName string
Input any
Options []approval.PermissionOption
}
ApprovalCall is a permission question a runtime asks about one tool call.
type BotAgentAuthPurger ¶
type BotAgentAuthPurger interface {
PurgeBotAgentAuth(ctx context.Context, botID, botAgentID string) error
}
BotAgentAuthPurger signs an Agent's runtime out: it removes the login the runtime keeps of its own.
type Caps ¶ added in v1.0.0
type Caps struct {
// Dependency is the managed workspace dependency providing the CLI, and
// Command the executable it installs. Both are empty for a runtime whose
// command comes from its configuration (custom ACP agents).
Dependency string
Command string
// ForkNeedsRuntime: the conversation's native session lives in its
// runtime metadata with no owner, so a Memoh-side copy would share it. A
// fork must then go through the runtime (ThreadForker); without one the
// conversation cannot be forked at all.
ForkNeedsRuntime bool
// ForkAnchorKey names the runtime metadata key holding the only turn a
// fork may start from. Empty: any turn can be forked.
ForkAnchorKey string
// ReadCommandsRequireIdle: a read command may open or replace the native
// session, so it waits for the conversation to be idle.
ReadCommandsRequireIdle bool
}
Caps is what a runtime declares about itself beyond the interfaces it implements: an optional capability is the interface (As finds it), never a flag repeating it.
func (Caps) ForkLatestOnly ¶ added in v1.0.0
ForkLatestOnly reports a runtime that forks only from its latest turn.
type Command ¶
type Command = turn.RuntimeCommand
type CommandKind ¶
type CommandKind = turn.RuntimeCommandKind
type CommandProvider ¶
type CommandProvider interface {
Commands(context.Context, PromptInput) ([]Command, error)
ReadCommand(context.Context, PromptInput) (CommandResult, error)
}
CommandProvider owns both the command vocabulary and read-only dispatch. Turn commands use Driver.Prompt; operation commands use Compactor.
type CommandResult ¶
type CommandResult = turn.RuntimeCommandResult
type CompactionResult ¶
CompactionResult returns updated native session references or usage. The Agent owns compaction and persists its own conversation files.
type Compactor ¶
type Compactor interface {
Compact(context.Context, PromptInput) (CompactionResult, error)
}
Compactor completes only when the runtime finishes compaction. Cancellation interrupts the operation. The caller owns the thread's execution slot and persists returned runtime metadata, without adding conversation messages.
type ControlCapabilities ¶
type ControlCapabilities = turn.RuntimeControlCapabilities
type Controls ¶
type Controls = turn.RuntimeControls
func ReadControls ¶
ReadControls reads the controls the runtime declares.
type DependencyMissingError ¶
type DependencyMissingError struct {
DependencyID string
TaskID string
// OperationInProgress distinguishes an existing administrative operation
// from a dependency that an administrator still needs to install.
OperationInProgress bool
}
DependencyMissingError reports that no copy of the dependency exists in the workspace. TaskID is the background installation task, if one was started.
func (*DependencyMissingError) Error ¶
func (e *DependencyMissingError) Error() string
func (*DependencyMissingError) Is ¶
func (*DependencyMissingError) Is(target error) bool
Is makes errors.Is(err, ErrDependencyMissing) true for any instance.
type DeviceLoginProvider ¶ added in v0.22.0
type DeviceLoginProvider interface {
StartDeviceLogin(ctx context.Context, botID, botAgentID string) (DeviceLoginStart, error)
// PollDeviceLogin reports the sign-in's state. On success the login is in
// place for the Agent; ownerUserID owns it where the runtime stores one.
PollDeviceLogin(ctx context.Context, ownerUserID, botID, botAgentID, loginID string) (DeviceLoginStatus, error)
CancelDeviceLogin(ctx context.Context, botID, botAgentID, loginID string) error
}
DeviceLoginProvider is implemented by direct runtimes whose account sign-in runs inside the Agent's own process: the agent obtains the device code, completes the sign-in, and writes its own login file.
type DeviceLoginStart ¶ added in v0.22.0
DeviceLoginStart is a device-code sign-in the runtime has begun: the user opens the URL and confirms the code there.
type DeviceLoginStatus ¶ added in v0.22.0
type DeviceLoginStatus struct {
// Status is one of the DeviceLogin states.
Status string
Error string
}
DeviceLoginStatus is the poll answer for a pending device-code sign-in.
type Driver ¶
type Driver interface {
// RuntimeType is the thread runtime type this driver serves (e.g. "codex").
RuntimeType() string
// Caps declares what the runtime supports.
Caps() Caps
// Prompt runs one turn. Stream events flow through input.Sink while the
// turn runs; the returned result carries the transcript for persistence.
// A context cancellation is an interrupt: the driver must stop the turn
// and still return the partial transcript it has.
Prompt(ctx context.Context, input PromptInput) (PromptResult, error)
}
Driver runs turns for one external agent runtime type.
type EventSink ¶
type EventSink interface {
EmitStreamEvent(event.StreamEvent)
}
EventSink receives stream events during a turn.
type EventSinkFunc ¶
type EventSinkFunc func(event.StreamEvent)
EventSinkFunc adapts a function to EventSink.
func (EventSinkFunc) EmitStreamEvent ¶
func (f EventSinkFunc) EmitStreamEvent(ev event.StreamEvent)
type Failure ¶ added in v0.21.0
type Failure struct {
Kind FailureKind
Err error
// Message is what the agent itself said about the failure, made fit to
// show and keep: users read it as they would in the agent's own client.
Message string
}
Failure is a runtime failure the user can act on. Like a public error it hides Err from errors.Is and errors.As: callers branch on Kind, and a cancellation or sentinel beneath it does not change how they treat it. Diagnostics still reach Err through Cause.
type FailureKind ¶ added in v0.21.0
type FailureKind int
FailureKind names a runtime failure the user can act on. There are three sorts: what the agent or its process said, shown as it said it (FailureReported); a sign-in the agent's protocol marked as such (FailureAuthRequired); and Memoh's own rules refusing a request, which have no upstream words (the rest). The application chooses the public error for each kind.
const ( // FailureReported: the agent or its process failed and said why; Message // is what it said. FailureReported FailureKind = iota + 1 // FailureAuthRequired: the runtime needs its account signed in or its // authentication configured. FailureAuthRequired // FailureGoalRequiresDefaultMode: a goal turn was asked for outside the // runtime's default mode. FailureGoalRequiresDefaultMode // is not one the runtime offers. FailureModeUnavailable // FailureCredential: the Agent's credential cannot be used. Failure.Err // is the agentcredential error that says why. FailureCredential // FailureCredentialBusy: the credential cannot change while a turn runs // on it. FailureCredentialBusy // FailureRuntimeBusy: the conversation's session is still serving a turn. FailureRuntimeBusy // FailureForkLatestOnly: the requested fork anchor is no longer the latest. FailureForkLatestOnly )
type Goal ¶
type Goal = turn.RuntimeGoal
type GoalProvider ¶
type GoalProvider interface {
Goal(context.Context, PromptInput) (*Goal, error)
ControlGoal(context.Context, PromptInput, string) error
}
GoalProvider requires structured state, pause/clear controls and resumption through an admitted /goal resume turn. A runtime with command-only goals exposes its native command via CommandProvider instead.
type Image ¶
type Image struct {
MimeType string
// Data is the raw image bytes (not base64, not a data URL).
Data []byte
}
Image is an inline prompt image.
type Launcher ¶
type Launcher struct {
// Path is the absolute path the driver must execute.
Path string
// Version is the observed CLI version, empty when unknown.
Version string
Source LauncherSource
}
Launcher is a resolved CLI executable inside the bot workspace.
type LauncherResolver ¶
type LauncherResolver interface {
ResolveLauncher(ctx context.Context, botID, depID string) (Launcher, error)
}
LauncherResolver picks the CLI copy a driver should execute: the managed copy first, then the image toolkit, then PATH. Discovery is read-only; a missing dependency yields a *DependencyMissingError.
type LauncherSource ¶
type LauncherSource string
LauncherSource says which copy of a CLI a Launcher points at.
const ( LauncherSourceManaged LauncherSource = "managed" LauncherSourceToolkit LauncherSource = "toolkit" LauncherSourcePath LauncherSource = "path" )
type Mode ¶
type Mode = turn.RuntimeMode
type ModeProvider ¶
type ModeState ¶
type ModeState = turn.RuntimeModeState
func PermissionModeState ¶ added in v1.0.0
PermissionModeState is a runtime's permission menu with current selected. A mode not on the menu is unavailable.
func PlanModeState ¶ added in v1.0.0
PlanModeState is the plan-mode switch every runtime with one offers: default or plan.
type ModelCatalog ¶
type ModelCatalog struct {
Models []ModelOption `json:"models"`
ConfiguredModelID string `json:"configured_model_id,omitempty"`
ConfiguredReasoningEffort string `json:"configured_reasoning_effort,omitempty"`
}
ModelCatalog is the runtime-owned model picker contract.
type ModelCatalogProvider ¶
type ModelCatalogProvider interface {
ModelCatalog(ctx context.Context, request ModelCatalogRequest) (ModelCatalog, error)
}
type ModelCatalogRequest ¶
type ModelCatalogRequest struct {
BotID string
BotAgentID string
ProjectPath string
// ModelID selects the model whose defaults the picker is displaying.
ModelID string
// Preference validation needs only capabilities; resolved defaults are a
// separate, optional observation for display.
ResolveDefaults bool
}
type ModelOption ¶
type ModelOption struct {
// ResolvedModelID preserves a runtime-advertised full model name for
// validation without duplicating its alias in the model picker.
ResolvedModelID string `json:"resolved_model_id,omitempty"`
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Default bool `json:"default,omitempty"`
DefaultReasoningEffort string `json:"default_reasoning_effort,omitempty"`
ReasoningEfforts []ReasoningEffortOption `json:"reasoning_efforts"`
UnavailablePermissionModes []string `json:"unavailable_permission_modes,omitempty"`
}
ModelOption is one runtime model and its supported reasoning options.
type PlanModeProvider ¶
type PlanModeProvider interface {
PlanMode(context.Context, PromptInput) (ModeState, error)
SetPlanMode(context.Context, PromptInput, string) (ModeState, error)
}
PlanModeProvider declares planning independently of tool permission presets.
type PromptInput ¶
type PromptInput struct {
Steering Steering
BotID string
BotAgentID string
ChatID string
ThreadID string
RunID string
RouteID string
// Prompt is the user's message text.
Prompt string
// ContextMarkdown is the assembled Memoh context document for this turn.
ContextMarkdown string
// Images are inline user images, raw bytes with MIME types.
Images []Image
// ModelID and ReasoningEffort are per-turn overrides; empty means the
// runtime's configured default.
ModelID string
ReasoningEffort string
// SessionMode is the Memoh session mode driving this turn (chat,
// schedule, ...); tool-gateway policy keys on it.
SessionMode string
// CurrentPlatform, ReplyTarget, and ConversationType describe the surface
// the turn is answering; they flow into the trusted tool identity.
CurrentPlatform string
ReplyTarget string
ConversationType string
// Command is an exact agent-command selector matched at admission; a
// runtime that advertises commands must re-validate it at dispatch.
// Runtimes without a command vocabulary ignore it.
Command string
// CommandArgs is the original user input after the runtime command selector.
CommandArgs string
// ForceFreshRuntime asks the driver to abandon any resumable runtime
// session and start this turn on a fresh one.
ForceFreshRuntime bool
// AttachmentReferences names non-image attachments already staged for the
// runtime (paths or references it may read through its tools).
AttachmentReferences []string
// CanFallbackImagesToFiles permits a runtime without image input to
// receive the images as workspace files instead of failing the turn.
CanFallbackImagesToFiles bool
// ToolOutputLimit bounds tool output the runtime feeds back into its
// context through Memoh-owned tool surfaces.
ToolOutputLimit contextlimit.ToolOutputLimit
// RuntimeMetadata is the session's runtime metadata map. Drivers read and
// persist their own keys through it (e.g. the codex thread id).
RuntimeMetadata map[string]any
// ContextURI names the Memoh-owned context document. The budget flows into
// runtime-hosted Memoh tools.
ContextURI string
ContextBudgetMaxTokens int
// RuntimeOwnerAccountID is the account whose workspace authority the
// runtime executes under.
RuntimeOwnerAccountID string
// ChannelIdentityID identifies the acting user for tool attribution.
ChannelIdentityID string
// SessionToken authenticates runtime-side calls back into Memoh.
SessionToken string //nolint:gosec // session credential material, not a hardcoded secret
// ToolHTTPURL is the Memoh tool gateway (HTTP MCP) base URL, empty when
// the gateway is unavailable.
ToolHTTPURL string
// CanRequestUserInput reports whether the surface driving this turn can
// deliver interactive decisions such as approvals and ask_user.
CanRequestUserInput bool
// Sink receives stream events as the turn runs. Never nil.
Sink EventSink
}
PromptInput is one turn's worth of work for a Driver.
func CompactionTurn ¶ added in v1.0.0
func CompactionTurn(input PromptInput, sessionKey string) (PromptInput, error)
CompactionTurn turns a control request into the silent turn a runtime runs its own compaction as: it needs the conversation's native session (stored at sessionKey), asks the user nothing, takes no steering, and none of its events become chat messages. The caller publishes the operation's state.
type PromptResult ¶
type PromptResult struct {
// Notices are UI-only runtime facts collected across startup and execution.
// They are persisted with the round, independently of the model transcript.
Notices []event.Notice
// SteerInputIDs correspond to the user messages in Output, in arrival order.
SteerInputIDs []string
// Output is the transcript to persist, in provider-message form.
Output []sdk.Message
// Text is the final assistant message text (for surfaces that report a
// plain-text result, e.g. schedule runs).
Text string
// Usage is the turn's token usage, when the runtime reported it.
Usage *sdk.Usage
// StopReason is the runtime's terminal stop reason, normalized to the
// event vocabulary where possible.
StopReason string
// AgentTurnID is the runtime's own identifier for this turn (e.g. the
// codex turn id); it anchors turn-level operations such as forking.
AgentTurnID string
// FinalTurnAnchorOnly restricts a multi-turn transcript to its final fork boundary.
FinalTurnAnchorOnly bool
// TurnCompleted reports whether the runtime finished the turn (as opposed
// to an interrupt or failure part-way).
TurnCompleted bool
// RuntimeMetadata carries driver-owned metadata updates to merge back
// into the session's runtime metadata (e.g. a newly created thread id).
// Nil means no changes.
RuntimeMetadata map[string]any
}
PromptResult is the durable outcome of one turn.
type Question ¶ added in v1.0.0
type Question struct {
ToolCallID string
// Input is the ask_user card's input.
Input any
// ProviderMetadata says which runtime request the answer goes back to.
ProviderMetadata map[string]any
}
Question is one question a runtime puts to the user.
type Quota ¶ added in v1.0.0
type Quota struct {
LimitReached bool
// Windows are the rolling usage windows, the shortest first.
Windows []QuotaWindow
}
Quota is the usage of the account an Agent's runtime is signed in to.
type QuotaReader ¶ added in v1.0.0
QuotaReader is implemented by runtimes whose account reports its usage.
type QuotaWindow ¶ added in v1.0.0
QuotaWindow is one rolling usage window.
type ReasoningEffortOption ¶
type ReasoningEffortOption struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
}
ReasoningEffortOption is one runtime-defined reasoning level.
type Registry ¶ added in v1.0.0
type Registry struct {
// contains filtered or unexported fields
}
Registry holds every external runtime's driver: the one place callers find a runtime, what it declares, and the interface behind a capability.
func NewRegistry ¶ added in v1.0.0
NewRegistry registers drivers, refusing one whose declaration cannot hold.
type SteerInput ¶
type Steering ¶
type Steering interface {
Enable(context.Context) error
Wake() <-chan struct{}
Next(context.Context) (SteerInput, bool, error)
Accepted(context.Context, string, int) error
Close(context.Context) error
}
Steering is the application-owned, fenced queue for the current run. Drivers enable it only after their native turn is ready to accept same-turn input. Accepted means the native runtime confirmed delivery; transcript persistence remains part of the external runtime's ordinary round commit.
type ThreadForker ¶
type ThreadForker interface {
ForkThread(ctx context.Context, botID, botAgentID string, runtimeMetadata map[string]any, lastTurnID string) (map[string]any, error)
}
ThreadForker is implemented by runtimes with native conversation forking. ForkThread derives a new runtime-side conversation from the session described by runtimeMetadata, cut after lastTurnID when non-empty (empty forks at the runtime head). It returns the runtime-metadata delta that identifies the fork — only the driver-owned session keys — which the caller overlays on the source session's runtime metadata.
type TranscriptRecorder ¶
type TranscriptRecorder struct {
// contains filtered or unexported fields
}
TranscriptRecorder folds stream events into the persisted round transcript. It is not capped by the UI event buffer.
func NewTranscriptRecorder ¶
func NewTranscriptRecorder(limits ...contextlimit.ToolOutputLimit) *TranscriptRecorder
NewTranscriptRecorder creates an empty transcript recorder.
func (*TranscriptRecorder) Add ¶
func (b *TranscriptRecorder) Add(ev event.StreamEvent)
Add folds one event into the transcript in arrival order.
func (*TranscriptRecorder) AddUser ¶
func (b *TranscriptRecorder) AddUser(text string)
AddUser inserts a confirmed mid-turn input between the surrounding output.
func (*TranscriptRecorder) Messages ¶
func (b *TranscriptRecorder) Messages(fallbackText string) []sdk.Message
Messages finalizes and returns the transcript. fallbackText is used when the runtime never streamed a text delta (some agents only return final text). Safe to call more than once; finalization is idempotent on the accumulated state.
type TurnStream ¶ added in v1.0.0
type TurnStream struct {
// contains filtered or unexported fields
}
TurnStream is a turn's one event stream: it records the turn and forwards it to the live consumer from its own goroutine. A runtime emits from the loop that reads its agent, so emitting never waits on the consumer: a slow stream would hold up every response, permission request and stop confirmation behind it. The agent's events, the decisions that settle after a stop, and the events of Memoh tools served through the gateway arrive on different paths; they queue here in arrival order, so the live stream and the persisted transcript agree.
While delivery lags, consecutive bare text or reasoning deltas fold into the pending tail, so the backlog grows with changes of event kind rather than with tokens, and a slow consumer receives fewer, larger deltas carrying the same text. How the text is split into deltas is not preserved.
func NewTurnStream ¶ added in v1.0.0
func NewTurnStream(next EventSink, limit contextlimit.ToolOutputLimit) *TurnStream
NewTurnStream starts the stream; Finish must be called to end it.
func (*TurnStream) EmitStreamEvent ¶ added in v1.0.0
func (s *TurnStream) EmitStreamEvent(ev event.StreamEvent)
EmitStreamEvent queues ev for the consumer and the transcript. After Finish it is dropped: the consumer may already be gone.
func (*TurnStream) Finish ¶ added in v1.0.0
func (s *TurnStream) Finish()
Finish stops taking events and returns once every accepted one has reached the consumer, so the consumer may be closed afterwards. Safe to call more than once.
func (*TurnStream) RecordTerminalDecision ¶ added in v1.0.0
func (s *TurnStream) RecordTerminalDecision(ev event.StreamEvent)
RecordTerminalDecision keeps ev in the transcript without a live frame.
func (*TurnStream) SteerInput ¶ added in v1.0.0
func (s *TurnStream) SteerInput(id, text string, accepted func())
SteerInput records user input the agent took mid-turn at this point of the turn; accepted (may be nil) runs once the events before it were delivered.
func (*TurnStream) SteerInputIDs ¶ added in v1.0.0
func (s *TurnStream) SteerInputIDs() []string
SteerInputIDs names the mid-turn inputs the turn took, in order, once every event has been delivered.
func (*TurnStream) Transcript ¶ added in v1.0.0
func (s *TurnStream) Transcript(finalText string) []sdk.Message
Transcript is the turn as persisted, once every event has been delivered.
type VersionObserver ¶
type VersionObserver interface {
ObserveLauncherVersion(ctx context.Context, botID, depID, version string)
}
VersionObserver lets drivers feed the CLI version reported during the protocol handshake back into the resolver's cache.
type Workspaces ¶ added in v1.0.0
type Workspaces interface {
bridge.Provider
bridge.WorkspaceInfoProvider
}
Workspaces gives a runtime the bridge into a bot's workspace; the workspace manager implements it.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package acp is Memoh's ACP core and its custom agents.
|
Package acp is Memoh's ACP core and its custom agents. |
|
client
Package client manages Agent Control Protocol processes, sessions, and events.
|
Package client manages Agent Control Protocol processes, sessions, and events. |
|
Package agentproc owns the lifecycle of the long-lived agent CLI processes that external agent runtimes keep in a bot's workspace.
|
Package agentproc owns the lifecycle of the long-lived agent CLI processes that external agent runtimes keep in a bot's workspace. |
|
Package claudecode implements the direct Claude Code runtime driver: it drives a Claude Code CLI inside the bot workspace over the stream-json wire protocol (NDJSON stdio plus the bidirectional control channel), with no ACP adapter and no Node sidecar in between.
|
Package claudecode implements the direct Claude Code runtime driver: it drives a Claude Code CLI inside the bot workspace over the stream-json wire protocol (NDJSON stdio plus the bidirectional control channel), with no ACP adapter and no Node sidecar in between. |
|
claudecfg
Package claudecfg holds the Bot Agent configuration contract for the direct Claude Code runtime.
|
Package claudecfg holds the Bot Agent configuration contract for the direct Claude Code runtime. |
|
Package codex implements the direct codex app-server runtime driver: it speaks the v2 protocol (internal/agent/runtime/external/codex/protocol) to a pinned codex CLI running inside the bot workspace, with no ACP adapter in between.
|
Package codex implements the direct codex app-server runtime driver: it speaks the v2 protocol (internal/agent/runtime/external/codex/protocol) to a pinned codex CLI running inside the bot workspace, with no ACP adapter in between. |
|
codexcfg
Package codexcfg holds the Bot Agent configuration contract for the direct codex runtime.
|
Package codexcfg holds the Bot Agent configuration contract for the direct codex runtime. |
|
protocol
Package protocol implements the wire contract Memoh speaks with the codex app-server: JSON-RPC 2.0 semantics over newline-delimited JSON on stdio, with the `jsonrpc` version field omitted, as the app-server does.
|
Package protocol implements the wire contract Memoh speaks with the codex app-server: JSON-RPC 2.0 semantics over newline-delimited JSON on stdio, with the `jsonrpc` version field omitted, as the app-server does. |
|
protocolgen
Package protocolgen generates the Go types for the codex app-server v2 protocol from the vendored JSON Schema snapshot under schema/.
|
Package protocolgen generates the Go types for the codex app-server v2 protocol from the vendored JSON Schema snapshot under schema/. |
|
Package grok implements the direct Grok Build runtime driver.
|
Package grok implements the direct Grok Build runtime driver. |
|
grokcfg
Package grokcfg holds the Bot Agent configuration contract for the direct Grok Build runtime.
|
Package grokcfg holds the Bot Agent configuration contract for the direct Grok Build runtime. |
|
Package toolmount serves the Memoh tool gateway (HTTP MCP) into a bot workspace over the bridge's reverse-HTTP stream, so an external agent runtime inside the container reaches Memoh tools at the workspace-local proxy URL.
|
Package toolmount serves the Memoh tool gateway (HTTP MCP) into a bot workspace over the bridge's reverse-HTTP stream, so an external agent runtime inside the container reaches Memoh tools at the workspace-local proxy URL. |