hermesacp

package module
v0.0.0-...-590b5fc Latest Latest
Warning

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

Go to latest
Published: Jul 5, 2026 License: GPL-3.0 Imports: 32 Imported by: 0

README

acp-go-hermes

acp-go-hermes is a Go ACP agent for Hermes. It speaks ACP on the provided stdin/stdout streams and runs one isolated hermes serve process for each ACP session.

Hermes owns model execution and native state. This package owns ACP dispatch, process launch, per-session HERMES_HOME isolation, WebSocket JSON-RPC event mapping, permission requests, config options, and hermes-state-db-v1 session storage.

Install

go install github.com/savid/acp-go-hermes/cmd/acp-go-hermes@latest

Local run:

go run ./cmd/acp-go-hermes -path "$(command -v hermes)"

The command reserves stdout for ACP JSON-RPC. Diagnostics go to stderr.

Embedded Go

err := hermesacp.Serve(ctx, input, output,
	hermesacp.WithExecutablePath("hermes"),
	hermesacp.WithHome("/tmp/hermes-acp-home"),
	hermesacp.WithDefaultModel("hermes/big-pickle"),
)

Public Surface

The package exports NewAgent, Serve, common process options, Hermes options, request builders, ForkSessionMethod, RawEventMethod, and the SessionStore API. Session durability uses:

const SessionStoreFormat = "hermes-state-db-v1"

Forking is available only through _hermes/session/fork.

Examples

go run ./examples/minimal-client "Reply with hello from ACP"
go run ./examples/interactive-chat
go run ./examples/resume-from-file

Development

make test
make test-integration-smoke
make audit

Live prompt, permission, and elicitation checks are guarded by ACP_GO_HERMES_RUN_LIVE_TOKENS=1.

Documentation

Overview

Package hermesacp exposes Hermes as an Agent Client Protocol agent.

The package runs one authenticated loopback `hermes serve` process per ACP session and maps native WebSocket JSON-RPC gateway events to ACP methods and notifications.

Index

Examples

Constants

View Source
const (
	ForkSessionMethod = "_hermes/session/fork"
	RawEventMethod    = "_hermes/rawEvent"
)
View Source
const (
	SessionStoreMainSubpath = ""
	SessionStoreFormat      = "hermes-state-db-v1"
)

Variables

This section is empty.

Functions

func DeleteSessionRequest

func DeleteSessionRequest(sessionID acp.SessionId) acp.UnstableDeleteSessionRequest

func ForkSessionRequest

func ForkSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.UnstableForkSessionRequest

func HTTPMCPServer

func HTTPMCPServer(name string, url string, headers map[string]string) acp.McpServer

func LoadSessionRequest

func LoadSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.LoadSessionRequest

func NewSessionRequest

func NewSessionRequest(cwd string, opts ...SessionRequestOption) acp.NewSessionRequest

func PromptRequest

func PromptRequest(sessionID acp.SessionId, blocks ...acp.ContentBlock) acp.PromptRequest

func ResumeSessionRequest

func ResumeSessionRequest(sessionID acp.SessionId, cwd string, opts ...SessionRequestOption) acp.ResumeSessionRequest

func Serve

func Serve(ctx context.Context, input io.Reader, output io.Writer, opts ...Option) error
Example (Initialize)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

clientToAgentReader, clientToAgentWriter := io.Pipe()
agentToClientReader, agentToClientWriter := io.Pipe()
defer clientToAgentReader.Close()
defer clientToAgentWriter.Close()
defer agentToClientReader.Close()
defer agentToClientWriter.Close()

done := make(chan error, 1)
go func() {
	done <- Serve(ctx, clientToAgentReader, agentToClientWriter)
}()

_, _ = fmt.Fprintln(clientToAgentWriter, `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1}}`)
line, _ := bufio.NewReader(agentToClientReader).ReadString('\n')
cancel()
_ = clientToAgentWriter.Close()
<-done

var response struct {
	Result struct {
		AuthMethods       []any `json:"authMethods"`
		AgentCapabilities struct {
			LoadSession     bool `json:"loadSession"`
			McpCapabilities struct {
				Http bool `json:"http"`
			} `json:"mcpCapabilities"`
		} `json:"agentCapabilities"`
	} `json:"result"`
}
_ = json.Unmarshal([]byte(line), &response)

fmt.Println(len(response.Result.AuthMethods) == 0)
fmt.Println(response.Result.AgentCapabilities.LoadSession)
fmt.Println(response.Result.AgentCapabilities.McpCapabilities.Http)
Output:
true
true
true

func SetModelRequest

func SetModelRequest(sessionID acp.SessionId, model string) acp.SetSessionConfigOptionRequest

func StdioMCPServer

func StdioMCPServer(name string, command string, args []string, env map[string]string) acp.McpServer

func TextPromptRequest

func TextPromptRequest(sessionID acp.SessionId, text string) acp.PromptRequest

Types

type Agent

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

Agent exposes Hermes through ACP.

func NewAgent

func NewAgent(opts ...Option) *Agent

func (*Agent) Authenticate

func (a *Agent) Authenticate(_ context.Context, params acp.AuthenticateRequest) (acp.AuthenticateResponse, error)

func (*Agent) Cancel

func (a *Agent) Cancel(ctx context.Context, params acp.CancelNotification) error

func (*Agent) Close

func (a *Agent) Close() error

func (*Agent) CloseSession

func (a *Agent) CloseSession(ctx context.Context, params acp.CloseSessionRequest) (acp.CloseSessionResponse, error)

func (*Agent) HandleExtensionMethod

func (a *Agent) HandleExtensionMethod(ctx context.Context, method string, params json.RawMessage) (any, error)

func (*Agent) Initialize

func (a *Agent) Initialize(_ context.Context, params acp.InitializeRequest) (acp.InitializeResponse, error)

func (*Agent) ListSessions

func (a *Agent) ListSessions(ctx context.Context, params acp.ListSessionsRequest) (acp.ListSessionsResponse, error)

func (*Agent) LoadSession

func (a *Agent) LoadSession(ctx context.Context, params acp.LoadSessionRequest) (acp.LoadSessionResponse, error)

func (*Agent) Logout

func (*Agent) NewSession

func (a *Agent) NewSession(ctx context.Context, params acp.NewSessionRequest) (acp.NewSessionResponse, error)

func (*Agent) Prompt

func (a *Agent) Prompt(ctx context.Context, params acp.PromptRequest) (acp.PromptResponse, error)

func (*Agent) ResumeSession

func (a *Agent) ResumeSession(ctx context.Context, params acp.ResumeSessionRequest) (acp.ResumeSessionResponse, error)

type ConcurrencyLimits

type ConcurrencyLimits struct {
	MaxActiveSessions        int
	MaxConcurrentPrompts     int
	MaxConcurrentClientCalls int
}

ConcurrencyLimits bounds work accepted by one Agent.

type HermesOption

type HermesOption func(*HermesOptions)

func WithHermesEnv

func WithHermesEnv(env map[string]string) HermesOption

func WithHermesModel

func WithHermesModel(model string) HermesOption

func WithHermesOutputSchema

func WithHermesOutputSchema(schema map[string]any) HermesOption

type HermesOptions

type HermesOptions struct {
	Model        string            `json:"model,omitempty"`
	Env          map[string]string `json:"env,omitempty"`
	OutputSchema map[string]any    `json:"outputSchema,omitempty"`
}

HermesOptions is the stable Hermes-specific subset accepted at _meta.hermes.options.

func NewHermesOptions

func NewHermesOptions(opts ...HermesOption) HermesOptions

func (HermesOptions) Meta

func (options HermesOptions) Meta() map[string]any

Meta returns an ACP _meta object for the supported Hermes-specific options.

type InMemorySessionStore

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

func NewInMemorySessionStore

func NewInMemorySessionStore() *InMemorySessionStore

func (*InMemorySessionStore) Append

func (s *InMemorySessionStore) Append(ctx context.Context, key SessionKey, entries []SessionStoreEntry) error

func (*InMemorySessionStore) Delete

func (s *InMemorySessionStore) Delete(ctx context.Context, key SessionKey) error

func (*InMemorySessionStore) ListSessions

func (s *InMemorySessionStore) ListSessions(ctx context.Context) ([]SessionSummary, error)

func (*InMemorySessionStore) ListSubkeys

func (s *InMemorySessionStore) ListSubkeys(ctx context.Context, key SessionKey) ([]string, error)

func (*InMemorySessionStore) Load

func (*InMemorySessionStore) Replace

func (s *InMemorySessionStore) Replace(ctx context.Context, main SessionKey, replacements []SessionStoreReplacement) error

type ListSessionsRequestOption

type ListSessionsRequestOption func(*acp.ListSessionsRequest)

func WithListSessionsCursor

func WithListSessionsCursor(cursor string) ListSessionsRequestOption

func WithListSessionsCwd

func WithListSessionsCwd(cwd string) ListSessionsRequestOption

func WithListSessionsMeta

func WithListSessionsMeta(meta map[string]any) ListSessionsRequestOption

type Option

type Option func(*Options)

Option configures the Hermes ACP agent.

func WithAgentName

func WithAgentName(name string) Option

func WithAgentTitle

func WithAgentTitle(title string) Option

func WithAgentVersion

func WithAgentVersion(version string) Option

func WithConcurrencyLimits

func WithConcurrencyLimits(limits ConcurrencyLimits) Option

func WithDefaultModel

func WithDefaultModel(model string) Option

func WithEnv

func WithEnv(env map[string]string) Option

func WithExecutablePath

func WithExecutablePath(path string) Option

func WithHome

func WithHome(path string) Option

WithHome sets the parent root under which isolated per-session Hermes homes are created. The adapter never shares the user's real Hermes home.

func WithLogger

func WithLogger(logger *slog.Logger) Option

func WithMeterProvider

func WithMeterProvider(provider metric.MeterProvider) Option

func WithSessionStore

func WithSessionStore(store SessionStore) Option

func WithSessionStoreLoadTimeout

func WithSessionStoreLoadTimeout(timeout time.Duration) Option

func WithTextMapPropagator

func WithTextMapPropagator(propagator propagation.TextMapPropagator) Option

func WithTracerProvider

func WithTracerProvider(provider trace.TracerProvider) Option

type Options

type Options struct {
	AgentName    string
	AgentTitle   string
	AgentVersion string

	ExecutablePath string
	Home           string
	DefaultModel   string
	Env            map[string]string

	Logger            *slog.Logger
	TracerProvider    trace.TracerProvider
	MeterProvider     metric.MeterProvider
	TextMapPropagator propagation.TextMapPropagator

	SessionStore            SessionStore
	SessionStoreLoadTimeout time.Duration
	ConcurrencyLimits       ConcurrencyLimits
	// contains filtered or unexported fields
}

Options configures the ACP agent process and Hermes sessions it starts.

type SessionKey

type SessionKey struct {
	SessionID string
	Subpath   string
}

type SessionRequestOption

type SessionRequestOption func(*sessionRequestConfig)

func WithSessionAdditionalDirectories

func WithSessionAdditionalDirectories(paths ...string) SessionRequestOption

func WithSessionHermesOptions

func WithSessionHermesOptions(options HermesOptions) SessionRequestOption

func WithSessionMCPServers

func WithSessionMCPServers(servers ...acp.McpServer) SessionRequestOption

func WithSessionMeta

func WithSessionMeta(meta map[string]any) SessionRequestOption

func WithSessionOutputSchema

func WithSessionOutputSchema(schema map[string]any) SessionRequestOption

func WithSessionRawEvents

func WithSessionRawEvents(enabled bool) SessionRequestOption

type SessionStore

type SessionStore interface {
	Append(ctx context.Context, key SessionKey, entries []SessionStoreEntry) error
	Load(ctx context.Context, key SessionKey) ([]SessionStoreEntry, error)
	Replace(ctx context.Context, main SessionKey, replacements []SessionStoreReplacement) error
	Delete(ctx context.Context, key SessionKey) error
	ListSessions(ctx context.Context) ([]SessionSummary, error)
	ListSubkeys(ctx context.Context, key SessionKey) ([]string, error)
}

type SessionStoreEntry

type SessionStoreEntry = json.RawMessage

type SessionStoreReplacement

type SessionStoreReplacement struct {
	Key     SessionKey
	Entries []SessionStoreEntry
}

type SessionSummary

type SessionSummary struct {
	SessionID          string
	UpdatedAtUnixMilli int64
	Cwd                string
	Title              string
	Meta               map[string]any
}

Directories

Path Synopsis
cmd
acp-go-hermes command
examples
minimal-client command
internal

Jump to

Keyboard shortcuts

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