Documentation
¶
Index ¶
- Constants
- Variables
- func AgentEventToSessionUpdate(event *adk.AgentEvent, opt *EventConverterOption) iter.Seq2[acpproto.SessionUpdate, error]
- func NewClientToolsMiddleware(ctx context.Context, cfg *Config) (adk.ChatModelAgentMiddleware, error)
- type ACPConn
- type Backend
- func (b *Backend) Edit(ctx context.Context, req *filesystem.EditRequest) error
- func (b *Backend) GlobInfo(ctx context.Context, req *filesystem.GlobInfoRequest) ([]filesystem.FileInfo, error)
- func (b *Backend) GrepRaw(ctx context.Context, req *filesystem.GrepRequest) ([]filesystem.GrepMatch, error)
- func (b *Backend) LsInfo(ctx context.Context, req *filesystem.LsInfoRequest) ([]filesystem.FileInfo, error)
- func (b *Backend) Read(ctx context.Context, req *filesystem.ReadRequest) (*filesystem.FileContent, error)
- func (b *Backend) Write(ctx context.Context, req *filesystem.WriteRequest) error
- type Config
- type EventConverterOption
- type InterruptConverter
Constants ¶
const ( MetaKeyInterrupted = "eino:interrupted" MetaKeyInterruptContexts = "eino:interruptContexts" )
Metadata keys used on ACP SessionUpdate _meta to carry eino-specific context. These form a cross-process contract with clients; changing them is a breaking change.
Variables ¶
var ( // ErrShellNonZeroExit is returned when a shell command exits with a non-zero code. ErrShellNonZeroExit = errors.New("acp.shell: non-zero exit") // ErrCapabilityMissing is returned when the client does not advertise the required capability. ErrCapabilityMissing = errors.New("acp: client capability not supported") // ErrOldStringNotFound is returned when Edit cannot locate the oldString in the file. ErrOldStringNotFound = errors.New("acp.edit: oldString not found") // ErrAmbiguousReplace is returned when multiple occurrences exist but ReplaceAll is false. ErrAmbiguousReplace = errors.New("acp.edit: ambiguous replacement (set ReplaceAll)") // ErrFileTooLarge is returned when Edit is attempted on a file exceeding maxEditFileSize. ErrFileTooLarge = errors.New("acp.edit: file too large for in-memory edit") )
Sentinel errors for structured error handling by callers.
Functions ¶
func AgentEventToSessionUpdate ¶
func AgentEventToSessionUpdate( event *adk.AgentEvent, opt *EventConverterOption, ) iter.Seq2[acpproto.SessionUpdate, error]
AgentEventToSessionUpdate converts an eino AgentEvent into a sequence of ACP SessionUpdate notifications. It handles message output (both streaming and non-streaming), tool calls, tool results, and interrupt events. For interrupt events, a custom InterruptConverter can be provided via opt; if nil, the default converter is used, which serializes the interrupt data as an AgentMessageChunk with interrupt metadata in _meta. When the upstream message output is a stream, tool-call argument chunks are concatenated into a single ToolCall update by default; set opt.PreserveToolCallStream to forward each chunk as its own update (see EventConverterOption.PreserveToolCallStream for the client-side reassembly contract).
func NewClientToolsMiddleware ¶
func NewClientToolsMiddleware(ctx context.Context, cfg *Config) (adk.ChatModelAgentMiddleware, error)
NewClientToolsMiddleware creates a ChatModelAgentMiddleware that bridges ACP client-side capabilities (filesystem read/write, terminal execution) to eino's filesystem tools. The ACP protocol only exposes read_text_file, write_text_file and terminal capabilities, so read_file and write_file are enabled only when the client advertises the corresponding capability. ls/glob/grep/edit are disabled by default; they become available when cfg.UseTerminalForFileTools is true and the client advertises the terminal capability — in which case they run as shell commands.
Types ¶
type ACPConn ¶
type ACPConn interface {
ReadTextFile(ctx context.Context, req acpproto.ReadTextFileRequest) (acpproto.ReadTextFileResponse, error)
WriteTextFile(ctx context.Context, req acpproto.WriteTextFileRequest) (acpproto.WriteTextFileResponse, error)
CreateTerminal(ctx context.Context, req acpproto.CreateTerminalRequest) (acpproto.CreateTerminalResponse, error)
WaitForTerminalExit(ctx context.Context, req acpproto.WaitForTerminalExitRequest) (acpproto.WaitForTerminalExitResponse, error)
TerminalOutput(ctx context.Context, req acpproto.TerminalOutputRequest) (acpproto.TerminalOutputResponse, error)
ReleaseTerminal(ctx context.Context, req acpproto.ReleaseTerminalRequest) (acpproto.ReleaseTerminalResponse, error)
}
ACPConn is the minimal interface for ACP client-side RPC calls used by Backend and shell. It is satisfied by *acpconn.AgentConnection (from the github.com/eino-contrib/acp/conn package). Callers may provide alternative implementations for testing or proxying.
type Backend ¶
type Backend struct {
// contains filtered or unexported fields
}
Backend implements the mfs.Backend interface on top of an ACP agent connection, bridging filesystem and shell tool calls to ACP client-side capabilities (read_text_file / write_text_file / terminal). It is exported so callers that build their own filesystem middleware (instead of using NewClientToolsMiddleware) can plug it directly into mfs.MiddlewareConfig.
func NewBackend ¶
NewBackend constructs a Backend from the same Config used by NewClientToolsMiddleware. The returned Backend reflects the capabilities advertised by the client:
- Read/Write are enabled when cfg.Capabilities.FS.ReadTextFile / WriteTextFile are set; otherwise calling them returns an error from the underlying ACP RPC.
- LsInfo/GlobInfo/GrepRaw (terminal-backed implementations) are only functional when cfg.Capabilities.Terminal is true AND cfg.UseTerminalForFileTools is set; otherwise they return an error.
- Edit requires both ReadTextFile and WriteTextFile fs capabilities; it performs a read-modify-write cycle via the fs API.
func (*Backend) Edit ¶
func (b *Backend) Edit(ctx context.Context, req *filesystem.EditRequest) error
func (*Backend) GlobInfo ¶
func (b *Backend) GlobInfo(ctx context.Context, req *filesystem.GlobInfoRequest) ([]filesystem.FileInfo, error)
func (*Backend) GrepRaw ¶
func (b *Backend) GrepRaw(ctx context.Context, req *filesystem.GrepRequest) ([]filesystem.GrepMatch, error)
func (*Backend) LsInfo ¶
func (b *Backend) LsInfo(ctx context.Context, req *filesystem.LsInfoRequest) ([]filesystem.FileInfo, error)
func (*Backend) Read ¶
func (b *Backend) Read(ctx context.Context, req *filesystem.ReadRequest) (*filesystem.FileContent, error)
func (*Backend) Write ¶
func (b *Backend) Write(ctx context.Context, req *filesystem.WriteRequest) error
type Config ¶
type Config struct {
// SessionID is the ACP session the middleware will operate on. Required.
SessionID acpproto.SessionID
// Conn is the agent-side ACP connection used to issue client requests. Required.
// Any implementation of ACPConn is accepted; *conn.AgentConnection (from
// github.com/eino-contrib/acp/conn) satisfies this interface and is the
// typical production choice.
Conn ACPConn
// Capabilities is the client capability set advertised during initialization.
// Required: tools are enabled based on what the client supports.
Capabilities *acpproto.ClientCapabilities
// UseTerminalForFileTools enables terminal-backed implementations of the
// ls, glob, and grep tools. It only takes effect when the client
// also advertises the terminal capability; otherwise those tools stay
// disabled because the ACP protocol does not expose corresponding
// filesystem methods.
//
// Note: edit always requires fs capability (ReadTextFile + WriteTextFile).
//
// Implementation: ls runs `ls -1A`, glob enumerates with `find` and matches
// in-process via doublestar, grep prefers ripgrep (`rg --json`) and
// transparently falls back to POSIX `grep -RnE` when `rg` is not
// installed on the client side.
UseTerminalForFileTools bool
// Logger is an optional structured logger for non-fatal diagnostics (e.g.
// ReleaseTerminal failures). If nil, slog.Default() is used.
Logger *slog.Logger
}
Config configures NewClientToolsMiddleware.
type EventConverterOption ¶
type EventConverterOption struct {
// InterruptConverter is an optional custom converter for interrupt events.
// If nil, the default conversion is used: the interrupt data is converted to
// an AgentMessageChunk with the interrupt metadata in _meta.
InterruptConverter InterruptConverter
// PreserveToolCallStream controls how an upstream tool-call stream is mapped
// into ACP SessionUpdates. ACP's ToolCall update has no native streaming
// concept for arguments, so by default (false) the converter concatenates
// every chunk into a single, complete ToolCall before yielding it. When set
// to true, each upstream chunk is forwarded as its own ToolCall SessionUpdate
// and the partial argument fragment is placed in RawInput as a JSON-encoded
// string (so it stays valid JSON on the wire).
//
// Whether the upstream is a stream at all is determined by the eino event
// (MessageVariant.IsStreaming), not by this flag — this flag only chooses
// between "preserve the stream" and "concat into one update" when it is.
//
// When true, the converter guarantees that ToolCallIDs do not interleave:
// once the emitted ToolCallID changes, the previous call is finalized and
// no further chunks for it will appear. Clients reassemble fragments by
// ToolCallID and treat an ID change as the end of the previous call.
PreserveToolCallStream bool
}
EventConverterOption configures the behavior of AgentEventToSessionUpdate.
type InterruptConverter ¶
type InterruptConverter func(info *adk.InterruptInfo) iter.Seq2[acpproto.SessionUpdate, error]
InterruptConverter converts an adk.InterruptInfo into a sequence of ACP SessionUpdates. Users can provide a custom implementation to control how interrupt events are presented to the client.