Documentation
¶
Overview ¶
Package grpcdriver implements the harness side of the mecatl.driver.v1 store-driver protocol: gRPC client adapters that satisfy the engine's store seams over a remote, operator-run driver process, plus the matching server wrappers a Go driver (or a test fixture) mounts over an in-process store.
- SessionStore implements port.SessionStore over SessionStoreService.
- MemoryStore implements tool.MemoryStore over MemoryStoreService.
- NewSessionStoreServer / NewMemoryStoreServer wrap an in-process store as the generated server interfaces (bufconn conformance fixtures today; promoting them to an importable location for external driver authors is deliberately deferred to a future DRIVERS.md — see docs/design/IMPLEMENTATION-NOTES.md).
Trust model ¶
A driver is OPERATOR-CONFIGURED INFRASTRUCTURE, sitting at the same trust tier as an on-disk store directory (the JSONL file the jsonlstore adapter writes): it holds whatever the harness persists, and a corrupt or hostile payload from it fails the harness-side decode loudly — it never reaches the model silently. Sanitization of model-written memory values stays in the harness's memory tools; a driver is never trusted to sanitize. The server wrappers deliberately install no authentication or TLS: mount them only on a separately protected operator network, or provide those controls in the driver host.
Wire format and versioning ¶
Session snapshots cross the wire as an OPAQUE, format-tagged envelope: the payload is exactly engine/adapter/sessnap's encoding and the format tag is SnapshotFormat ("sessnap-json/1"). The driver stores and returns the envelope verbatim and never decodes it. Snapshot schema evolution lives in sessnap (additive JSON fields); the envelope's format tag changes ONLY if the encoding itself is replaced. Load rejects an unknown format with an infrastructure error — never ErrNotFound.
Resilience posture ¶
Deadline passthrough only: the caller's ctx deadline rides the RPC, there are NO retries, NO default deadline, and NO transient/permanent error classification — store consumers already treat Save/Load errors as unit failures. If drivers ever need retries/breakers the house pattern is a resilience DECORATOR over these clients (the llmresilience precedent), not knobs here. Dial is lazy (grpc.NewClient): the first RPC surfaces a connect error.
Index ¶
- Constants
- Variables
- func Dial(target string, opts ...Option) (*grpc.ClientConn, error)
- func NegotiateMemoryStore(ctx context.Context, conn grpc.ClientConnInterface) (tool.MemoryStore, error)
- func NewAgentSourceServer(src tool.AgentDefSource) driverv1.AgentSourceServiceServer
- func NewCommandSourceServer(src prompt.CommandSource) driverv1.CommandSourceServiceServer
- func NewEventLogServer(log port.EventLog) driverv1.EventLogServiceServer
- func NewMemoryStoreServer(st tool.MemoryStore) driverv1.MemoryStoreServiceServer
- func NewScheduleOneShotReArmerServer(reArmer port.ScheduleOneShotReArmer) driverv1.ScheduleOneShotReArmerServiceServer
- func NewScheduleStoreServer(st port.ScheduleStore) driverv1.ScheduleStoreServiceServer
- func NewSessionLeaseServer(lease port.SessionLease) driverv1.SessionLeaseServiceServer
- func NewSessionStoreServer(st port.SessionStore) driverv1.SessionStoreServiceServer
- func NewSkillSourceServer(src tool.SkillSource) driverv1.SkillSourceServiceServer
- func NewSoulSourceServer(src prompt.SoulSource) driverv1.SoulSourceServiceServer
- type AgentOptions
- type AgentSource
- type CommandOptions
- type CommandSource
- type EventLog
- type MemoryConvergenceStore
- type MemoryLifecycleStore
- func (st *MemoryLifecycleStore) ForgetVersioned(ctx context.Context, key string, expected tool.MemoryVersion) (tool.MemoryRecord, error)
- func (st *MemoryLifecycleStore) Inspect(ctx context.Context, key string) (tool.MemoryRecord, bool, error)
- func (st *MemoryLifecycleStore) RememberVersioned(ctx context.Context, entry tool.MemoryEntry, expected tool.MemoryVersion) (tool.MemoryRecord, error)
- func (st *MemoryLifecycleStore) UndoLatest(ctx context.Context, key string, expected tool.MemoryVersion) (tool.MemoryRecord, error)
- type MemoryStore
- func (st *MemoryStore) Forget(ctx context.Context, key string) error
- func (st *MemoryStore) Index(ctx context.Context) ([]tool.MemoryEntry, error)
- func (st *MemoryStore) List(ctx context.Context, prefix string) ([]tool.MemoryEntry, error)
- func (st *MemoryStore) Recall(ctx context.Context, key string) (tool.MemoryEntry, bool, error)
- func (st *MemoryStore) RememberEntry(ctx context.Context, e tool.MemoryEntry) error
- func (st *MemoryStore) Search(ctx context.Context, query string, k int) ([]tool.MemoryEntry, error)
- type Option
- type ScheduleStore
- func (st *ScheduleStore) Claim(ctx context.Context, name string, now, nextFire time.Time) (port.Schedule, error)
- func (st *ScheduleStore) ClaimNow(ctx context.Context, name string, now, nextFire time.Time) (port.Schedule, error)
- func (st *ScheduleStore) Delete(ctx context.Context, name string) error
- func (st *ScheduleStore) Due(ctx context.Context, now time.Time) ([]port.Schedule, error)
- func (st *ScheduleStore) List(ctx context.Context) ([]port.Schedule, error)
- func (st *ScheduleStore) ListFires(ctx context.Context, scheduleName string) ([]port.ScheduleFire, error)
- func (st *ScheduleStore) Load(ctx context.Context, name string) (port.Schedule, error)
- func (st *ScheduleStore) LoadFire(ctx context.Context, fireID string) (port.ScheduleFire, error)
- func (st *ScheduleStore) ReArmOneShot(ctx context.Context, name string, nextFire time.Time) error
- func (st *ScheduleStore) RecordFire(ctx context.Context, f port.ScheduleFire) error
- func (st *ScheduleStore) RecordFireProgress(ctx context.Context, name string, fireID string, at time.Time) error
- func (st *ScheduleStore) RecordFireStart(ctx context.Context, name string, fire port.ScheduleFire) error
- func (st *ScheduleStore) Save(ctx context.Context, s port.Schedule) error
- func (st *ScheduleStore) SetEnabled(ctx context.Context, name string, enabled bool) error
- type SessionLease
- type SessionStore
- func (st *SessionStore) Delete(ctx context.Context, id session.SessionID) error
- func (st *SessionStore) List(ctx context.Context) ([]port.StoredSession, error)
- func (st *SessionStore) Load(ctx context.Context, id session.SessionID) (*session.Session, error)
- func (st *SessionStore) PageSessionMetadata(ctx context.Context, request port.SessionMetadataPageRequest) (port.SessionMetadataPage, error)
- func (st *SessionStore) Save(ctx context.Context, s *session.Session) error
- func (st *SessionStore) SupportsSessionDelete() bool
- type SkillSource
- func (s *SkillSource) ListSkillAssets(ctx context.Context, name string) ([]tool.SkillAsset, error)
- func (s *SkillSource) ListSkills(ctx context.Context) ([]tool.SkillMeta, error)
- func (s *SkillSource) ReadSkillAsset(ctx context.Context, skill, asset string) ([]byte, error)
- func (s *SkillSource) SkillBody(ctx context.Context, name string) (string, error)
- type SoulOptions
- type SoulSource
- type TLSOptions
Constants ¶
const EventLogFormat = "eventlog-json/1"
EventLogFormat is the event-log envelope format tag this client writes on Append and accepts on Read: the payload is exactly json.Marshal of a session.Event (one event per message). It is the SAME tag the local jsonlstore writes inside its {"v":...,"ev":...} on-disk record (jsonlstore.eventLogFormat) — the wire and the file version the SAME event encoding, so a log written by one and read by the other agrees. The driver round-trips the tag verbatim; it changes only if the event encoding itself is replaced (session.Event's own schema evolution is additive and needs no bump). Read rejects any other tag as an infrastructure fault — a forward-incompatible log must fail loud, never silently skip.
SIGNPOST — a future format bump MUST be read-set-accept / write-newest: the readers (this client's Read, the server wrapper's Append decode-or-passthrough) must keep ACCEPTING every previously-shipped tag while Append WRITES only the newest. The driver round-trips envelopes verbatim and cannot migrate them.
const MaxSnapshotBytes = 64 << 20
MaxSnapshotBytes is the protocol's REQUIRED MINIMUM message capacity for a snapshot envelope: 64 MiB. A session snapshot legitimately reaches multiple MiB (inline media parts alone may carry session.MaxPromptMediaBytes = 20 MiB in one prompt, base64-inflated by sessnap's JSON encoding), so gRPC's default 4 MiB receive cap would brick Save/Load mid-session. Dial raises the client's per-call send AND receive limits to this value; a conforming driver MUST accept payloads up to it on its server too (grpc.MaxRecvMsgSize(MaxSnapshotBytes) — see the server-wrapper notes in server.go and the SessionSnapshot doc in session_store.proto). Pinned by the storeconformance "large snapshot" subtest run over bufconn.
const ScheduleFormat = "schedule-json/1"
ScheduleFormat is the schedule/fire-record envelope format tag this client writes on Save/RecordFire* and accepts on Load/LoadFire/List*: the payload is exactly `encoding/json` of a `port.Schedule` / `port.ScheduleFire` (the same encoding the in-process jsonlstore/redisstore persist). The driver round-trips the tag verbatim; it changes ONLY if the encoding itself is replaced (the Schedule/ScheduleFire structs' own schema evolution is additive and needs no bump). Load/LoadFire reject any other tag with an infrastructure error — never ErrScheduleNotFound.
SIGNPOST — a future format bump MUST be read-set-accept / write-newest: the readers (this client's Load/LoadFire, the server wrapper's Save/RecordFire* decode) must keep ACCEPTING every previously-shipped format tag while Save/RecordFire* WRITE only the newest. The driver round-trips envelopes verbatim and cannot migrate them — a bump that switches the write tag and rejects the old tag in the same step bricks every schedule/fire already stored under the old format.
const SnapshotFormat = "sessnap-json/1"
SnapshotFormat is the snapshot envelope format tag this client writes on Save and accepts on Load: the payload is exactly sessnap.Marshal output (one JSON line). The driver round-trips the tag verbatim; it changes ONLY if the encoding itself is replaced (sessnap's own schema evolution is additive and needs no bump). Load rejects any other tag with an infrastructure error — never ErrNotFound.
SIGNPOST — a future format bump MUST be read-set-accept / write-newest: the readers (this client's Load, the server wrapper's Save decode) must keep ACCEPTING every previously-shipped format tag while Save WRITES only the newest. A bump that switches the write tag and rejects the old tag in the same step bricks every session already stored under the old format — the driver round-trips envelopes verbatim and cannot migrate them.
Variables ¶
var ErrMemoryLifecycleUnsupported = errors.New("remote memory driver does not support lifecycle operations")
ErrMemoryLifecycleUnsupported reports an old/base-only remote driver. Base memory operations remain usable; irreversible lifecycle operations never silently downgrade.
var ErrNotFound = fmt.Errorf("grpcdriver: session not found: %w", port.ErrSessionNotFound)
ErrNotFound is returned by Load when the driver has no snapshot under the given id. It wraps port.ErrSessionNotFound so a consumer that may not import this adapter can distinguish not-found from an infra failure via errors.Is.
Functions ¶
func Dial ¶
func Dial(target string, opts ...Option) (*grpc.ClientConn, error)
Dial connects to a store driver at target ("host:port") per opts. The connection is LAZY (grpc.NewClient): the first RPC surfaces a connect error. Plaintext is the LOCAL single-user default (loopback hosts and unix sockets); ANY other target requires WithTLS — token or not (see the cleartext refusal in dialOptions).
func NegotiateMemoryStore ¶
func NegotiateMemoryStore(ctx context.Context, conn grpc.ClientConnInterface) (tool.MemoryStore, error)
NegotiateMemoryStore reads the explicit optional-capability signal once and returns either the base client or a distinct lifecycle-capable wrapper. Unimplemented means an older valid driver; every other negotiation failure is returned rather than silently changing the catalog.
func NewAgentSourceServer ¶
func NewAgentSourceServer(src tool.AgentDefSource) driverv1.AgentSourceServiceServer
NewAgentSourceServer wraps src as an AgentSourceService driver server.
func NewCommandSourceServer ¶
func NewCommandSourceServer(src prompt.CommandSource) driverv1.CommandSourceServiceServer
NewCommandSourceServer wraps src as a CommandSourceService driver server.
func NewEventLogServer ¶
func NewEventLogServer(log port.EventLog) driverv1.EventLogServiceServer
NewEventLogServer wraps log as an EventLogService driver server.
func NewMemoryStoreServer ¶
func NewMemoryStoreServer(st tool.MemoryStore) driverv1.MemoryStoreServiceServer
NewMemoryStoreServer wraps st as a MemoryStoreService driver server.
func NewScheduleOneShotReArmerServer ¶
func NewScheduleOneShotReArmerServer(reArmer port.ScheduleOneShotReArmer) driverv1.ScheduleOneShotReArmerServiceServer
NewScheduleOneShotReArmerServer wraps reArmer as a ScheduleOneShotReArmerService driver server.
func NewScheduleStoreServer ¶
func NewScheduleStoreServer(st port.ScheduleStore) driverv1.ScheduleStoreServiceServer
NewScheduleStoreServer wraps st as a ScheduleStoreService driver server.
func NewSessionLeaseServer ¶
func NewSessionLeaseServer(lease port.SessionLease) driverv1.SessionLeaseServiceServer
NewSessionLeaseServer wraps lease as a SessionLeaseService driver server.
func NewSessionStoreServer ¶
func NewSessionStoreServer(st port.SessionStore) driverv1.SessionStoreServiceServer
NewSessionStoreServer wraps st as a SessionStoreService driver server.
func NewSkillSourceServer ¶
func NewSkillSourceServer(src tool.SkillSource) driverv1.SkillSourceServiceServer
NewSkillSourceServer wraps src as a SkillSourceService driver server.
func NewSoulSourceServer ¶
func NewSoulSourceServer(src prompt.SoulSource) driverv1.SoulSourceServiceServer
NewSoulSourceServer wraps src as a SoulSourceService driver server. The wrapped Go source already upholds the fail-soft contract; the harness CLIENT re-validates the body regardless (it never trusts a driver to sanitize).
Types ¶
type AgentOptions ¶
type AgentOptions struct {
// Diagnostics is the operational-logging sink for the defensive-drop WARNs
// (an over-cap def, the def-count ceiling). nil defaults to
// port.NopDiagnostics.
Diagnostics port.Diagnostics
}
AgentOptions configures a remote AgentSource client.
type AgentSource ¶
type AgentSource struct {
// contains filtered or unexported fields
}
AgentSource is a tool.AgentDefSource over a remote AgentSourceService driver. It is translation plus a DEFENSIVE normalization layer (the driver sits at the operator-infrastructure trust tier, but its metadata feeds the always-in-context Subagent roster and per-def system prompts, so the client re-enforces the invariants the port promises rather than trusting the wire): names are TRIMMED before every use (the FS parser trims frontmatter names; the wire client must not be weaker), blank-name defs are dropped, duplicate names de-dup first-wins, the result is name-sorted, descriptions are forced single-line then re-truncated to tool.MaxAgentDescriptionBytes, bodies are re-truncated to tool.MaxAgentBodyBytes, per-def collection sizes are count-capped (see the caps above — an over-cap def is dropped with a WARN), hooks/headers are re-normalized via the SAME exported helpers the parser uses (agents.NormalizeHooks/NormalizeHeaders), and Origin is stamped AgentOriginDriver UNCONDITIONALLY — a driver-served def IS driver tier; a driver must not claim the "project"/"user" admission labels (the wire origin field stays driver-side observability only).
func NewAgentSource ¶
func NewAgentSource(conn grpc.ClientConnInterface, opts AgentOptions) *AgentSource
NewAgentSource wraps an established driver connection (see Dial) as a tool.AgentDefSource.
func (*AgentSource) ListAgentDefs ¶
ListAgentDefs returns the driver's definition snapshot, defensively normalized (see the type doc).
type CommandOptions ¶
type CommandOptions struct {
// Diagnostics is the operational-logging sink for the RUNTIME fail-soft
// branches (a driver fault during a run degrades to "no commands from this
// source" with a WARN, never an aborted run). nil defaults to
// port.NopDiagnostics.
Diagnostics port.Diagnostics
}
CommandOptions configures a remote CommandSource client.
type CommandSource ¶
type CommandSource struct {
// contains filtered or unexported fields
}
CommandSource is a prompt.CommandSource over a remote CommandSourceService driver. LIVE semantics: every Expand/List consults the driver (no snapshot, matching the file expander's reads-current-files discipline) — and deliberately NO latching: a transient fault must not latch a command "missing", and grammar-invalid names are re-dropped statelessly per List.
Defensive normalization on List (the driver is operator infrastructure, but the metadata feeds the palette): names that violate the invocation grammar are DROPPED (prompt.ValidCommandName — they could never be invoked), duplicates de-dup first-wins, the result is name-sorted, and descriptions are forced single-line then rune-capped to prompt.MaxCommandDescriptionRunes.
Fault posture: a RUNTIME fault fail-softs — ListCommands → (nil, nil) + WARN (prompt.MultiExpander.List aborts the whole palette walk on a child error, so a transient driver blip must not propagate), CommandBody → ("", false, nil) + WARN (the raw input passes through). A caller-cancelled ctx still surfaces (rpcErr rewraps so errors.Is(ctx.Err()) holds), as does the server's INVALID_ARGUMENT pre-validation (a programming error, not a blip). The BUILD-time reachability check is the separate Probe (loud-misconfig posture, fatal in the composition layer).
func NewCommandSource ¶
func NewCommandSource(conn grpc.ClientConnInterface, opts CommandOptions) *CommandSource
NewCommandSource wraps an established driver connection (see Dial) as a prompt.CommandSource.
func (*CommandSource) CommandBody ¶
CommandBody returns the named command's RAW template. A driver NOT_FOUND is the NORMAL unknown-command outcome (found=false, nil error → the input passes through unchanged); a runtime fault degrades the same way with a WARN; a caller-cancelled ctx and a server INVALID_ARGUMENT (blank name — pre-validated server-side) surface as non-nil errors.
func (*CommandSource) ListCommands ¶
ListCommands returns the driver's CURRENT command metadata, defensively normalized (see the type doc). A runtime driver fault degrades to (nil, nil) with a WARN.
func (*CommandSource) Probe ¶
func (s *CommandSource) Probe(ctx context.Context) error
Probe performs the BUILD-time reachability check: one ListCommands round trip, returning the wrapped RPC error on a fault (the composition layer treats it as FATAL — an explicitly configured driver that cannot answer is a misconfiguration, unlike a runtime blip which the live calls degrade on). The command set itself is NOT judged: an empty set is a legal "no commands".
type EventLog ¶
type EventLog struct {
// contains filtered or unexported fields
}
EventLog is a port.EventLog over a remote EventLogService driver. Encode (session.Event → JSON) happens HERE on Append and decode (JSON → session.Event) HERE on Read, harness-side: the driver only ever sees the opaque format-tagged envelope, exactly as the SessionStore driver keeps sessnap harness-side.
func NewEventLog ¶
func NewEventLog(conn grpc.ClientConnInterface) *EventLog
NewEventLog wraps an established driver connection (see Dial) as a port.EventLog.
func (*EventLog) Append ¶
Append encodes ev to its session.Event JSON and records it under id on the driver, in append order. A marshal failure is a client-side error (no RPC). The relay treats any non-nil error as "not recorded" and WARNs.
func (*EventLog) Read ¶
Read streams the session's recorded events from the driver and decodes each envelope back into a session.Event, yielding them in append order. An empty stream (a session never appended to) yields an EMPTY sequence — absence is data, never an error. A mid-stream fault — an unknown envelope format, a payload that fails to decode, or an RPC/stream error — yields (session.Event{}, err) and then stops, honouring the port.EventLog contract (Read yields no further events after an error).
type MemoryConvergenceStore ¶
type MemoryConvergenceStore struct{ *MemoryLifecycleStore }
MemoryConvergenceStore is the negotiated presence-and-version CAS view.
func (*MemoryConvergenceStore) RememberIfCurrent ¶
func (st *MemoryConvergenceStore) RememberIfCurrent(ctx context.Context, entry tool.MemoryEntry, expected tool.MemoryCurrent) (tool.MemoryRecord, error)
RememberIfCurrent invokes the separately negotiated atomic convergence RPC.
type MemoryLifecycleStore ¶
type MemoryLifecycleStore struct{ *MemoryStore }
MemoryLifecycleStore is the negotiated lifecycle-capable view of MemoryStore. It is returned only after the remote driver successfully answers a lifecycle probe, so base-only drivers never accidentally advertise optional tools.
func (*MemoryLifecycleStore) ForgetVersioned ¶
func (st *MemoryLifecycleStore) ForgetVersioned(ctx context.Context, key string, expected tool.MemoryVersion) (tool.MemoryRecord, error)
ForgetVersioned never downgrades to legacy Forget because doing so would lose compare-version protection and history.
func (*MemoryLifecycleStore) Inspect ¶
func (st *MemoryLifecycleStore) Inspect(ctx context.Context, key string) (tool.MemoryRecord, bool, error)
Inspect returns lifecycle data from the positively negotiated driver. A missing or failing lifecycle RPC is not reinterpreted as a legacy Recall.
func (*MemoryLifecycleStore) RememberVersioned ¶
func (st *MemoryLifecycleStore) RememberVersioned(ctx context.Context, entry tool.MemoryEntry, expected tool.MemoryVersion) (tool.MemoryRecord, error)
RememberVersioned uses the lifecycle RPC selected by negotiation. Once a driver advertises lifecycle support, any RPC failure is a protocol/operation error; the capable client never downgrades to legacy unconditional writes.
func (*MemoryLifecycleStore) UndoLatest ¶
func (st *MemoryLifecycleStore) UndoLatest(ctx context.Context, key string, expected tool.MemoryVersion) (tool.MemoryRecord, error)
UndoLatest requires lifecycle support and never silently degrades.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is a tool.MemoryStore over a remote MemoryStoreService driver. It is PURE TRANSLATION: every behavioral guarantee (key validation, sorting, value omission on Index/Search, determinism) is the DRIVER's, and the memconformance suite run over this client is what pins it. Sanitization of model-written values stays harness-side in the memory tools.
func NewMemoryStore ¶
func NewMemoryStore(conn grpc.ClientConnInterface) *MemoryStore
NewMemoryStore wraps an established driver connection (see Dial) as a tool.MemoryStore.
func (*MemoryStore) Forget ¶
func (st *MemoryStore) Forget(ctx context.Context, key string) error
Forget deletes the entry for key on the driver; a missing key is not an error (idempotent).
func (*MemoryStore) Index ¶
func (st *MemoryStore) Index(ctx context.Context) ([]tool.MemoryEntry, error)
Index returns the driver's tier-0 routing table: key-sorted entries with values omitted and descriptions filled.
func (*MemoryStore) List ¶
func (st *MemoryStore) List(ctx context.Context, prefix string) ([]tool.MemoryEntry, error)
List returns all entries whose key has the given prefix (empty = all), key-sorted by the driver, values present.
func (*MemoryStore) Recall ¶
func (st *MemoryStore) Recall(ctx context.Context, key string) (tool.MemoryEntry, bool, error)
Recall returns the entry for the exact key. A driver miss (found=false) is (zero, false, nil) — never an error.
func (*MemoryStore) RememberEntry ¶
func (st *MemoryStore) RememberEntry(ctx context.Context, e tool.MemoryEntry) error
RememberEntry stores e on the driver, overwriting any existing entry under e.Key. The driver stamps UpdatedAt on write (the input value is advisory); a blank/whitespace-only key surfaces the driver's INVALID_ARGUMENT.
func (*MemoryStore) Search ¶
func (st *MemoryStore) Search(ctx context.Context, query string, k int) ([]tool.MemoryEntry, error)
Search returns up to k entries relevant to query, best-first per the driver's (deterministic) ranking, values omitted. k <= 0 selects the driver's default page size; a blank query yields an empty result.
type Option ¶
type Option func(*dialConfig)
Option customises Dial.
func WithBearerToken ¶
WithBearerToken attaches a per-RPC bearer credential ("authorization: Bearer <token>"). For a non-loopback target the credential demands transport security, so the token can never ride a cleartext wire to a remote host.
func WithTLS ¶
func WithTLS(o TLSOptions) Option
WithTLS enables transport TLS per o (a zero o verifies against the system roots with no client certificate).
type ScheduleStore ¶
type ScheduleStore struct {
// contains filtered or unexported fields
}
ScheduleStore is a port.ScheduleStore (and, unconditionally, a port.ScheduleOneShotReArmer) over a remote ScheduleStoreService / ScheduleOneShotReArmerService driver. Encode/decode happens HERE (encoding/json of port.Schedule / port.ScheduleFire), harness-side: the driver only ever sees the opaque, format-tagged envelope, exactly as the SessionStore driver keeps sessnap harness-side.
The client implements the OPTIONAL ScheduleOneShotReArmer UNCONDITIONALLY — the PrunableStore precedent: a driver that does not serve the re-arm service answers ReArmOneShot with UNIMPLEMENTED, which this client maps to port.ErrScheduleUnsupported (the sticky-disable sentinel, the ErrLeaseUnsupported precedent); composition then logs one INFO and stickily disables the one-shot re-arm path (byte-identical to the pre-Phase-2 at-most-once posture). This is the production degradation path, not an error: a driver serving only ScheduleStoreService still conforms.
func NewScheduleStore ¶
func NewScheduleStore(conn grpc.ClientConnInterface) *ScheduleStore
NewScheduleStore wraps an established driver connection (see Dial) as a port.ScheduleStore. The connection serves BOTH ScheduleStoreService AND ScheduleOneShotReArmerService over the same conn; a driver that omits the re-arm service is tolerated (ReArmOneShot maps its UNIMPLEMENTED to port.ErrScheduleUnsupported).
func (*ScheduleStore) Claim ¶
func (st *ScheduleStore) Claim(ctx context.Context, name string, now, nextFire time.Time) (port.Schedule, error)
Claim is the at-most-once atomic advance over the wire. The driver applies it atomically (the durable NextFireAt advance IS the at-most-once fence — the harness client cannot fence over the wire); a zero nextFire is the "no further fire" sentinel. A driver NOT_FOUND maps to port.ErrScheduleNotFound.
func (*ScheduleStore) ClaimNow ¶
func (st *ScheduleStore) ClaimNow(ctx context.Context, name string, now, nextFire time.Time) (port.Schedule, error)
ClaimNow is the manual-trigger variant of Claim over the wire (no due-check). The driver fences on LastFireAt: a ClaimNow at the SAME now as a prior ClaimNow is rejected (the driver maps that to an error the harness surfaces). A driver NOT_FOUND maps to port.ErrScheduleNotFound.
func (*ScheduleStore) Delete ¶
func (st *ScheduleStore) Delete(ctx context.Context, name string) error
Delete removes the schedule stored under name on the driver. It is idempotent harness-side: a driver NOT_FOUND (a thin driver surfacing its primitive's miss) maps to success, per the port.ScheduleStore contract.
func (*ScheduleStore) Due ¶
Due returns the schedules whose NextFireAt is <= now AND Enabled AND (when MaxFires > 0) FireCount < MaxFires. The driver computes the due set; the records are decoded harness-side.
func (*ScheduleStore) List ¶
List returns the driver's full stored-schedule inventory. The records are decoded harness-side; an unknown envelope format or undecodable payload on any record is an infrastructure error.
func (*ScheduleStore) ListFires ¶
func (st *ScheduleStore) ListFires(ctx context.Context, scheduleName string) ([]port.ScheduleFire, error)
ListFires returns the fire records for a schedule. An unknown SCHEDULE maps to port.ErrScheduleNotFound; an empty fire list for an existing schedule is a successful empty slice.
func (*ScheduleStore) Load ¶
Load fetches the schedule stored under name from the driver and decodes it. A driver NOT_FOUND maps to port.ErrScheduleNotFound (wrapped); an unknown envelope format, a payload that fails to decode, or a decoded schedule whose Spec.Name is NOT the requested one (a mis-keyed driver) is an infrastructure error, never not-found.
func (*ScheduleStore) LoadFire ¶
func (st *ScheduleStore) LoadFire(ctx context.Context, fireID string) (port.ScheduleFire, error)
LoadFire fetches the fire record stored under fireID from the driver and decodes it. A driver NOT_FOUND maps to port.ErrScheduleNotFound (wrapped); an unknown envelope format, a payload that fails to decode, or a decoded fire whose ID is NOT the requested one (a mis-keyed driver) is an infrastructure error, never not-found.
func (*ScheduleStore) ReArmOneShot ¶
ReArmOneShot re-enables the named one-shot schedule, sets its NextFireAt to nextFire, and increments OneShotRetryCount over the wire. The driver applies it atomically (the at-most-once fence for the re-arm). A driver NOT_FOUND maps to port.ErrScheduleNotFound. A driver that does not serve the re-arm service answers UNIMPLEMENTED → port.ErrScheduleUnsupported (the sticky- disable sentinel; the production degradation path — see the type doc).
func (*ScheduleStore) RecordFire ¶
func (st *ScheduleStore) RecordFire(ctx context.Context, f port.ScheduleFire) error
RecordFire records the terminal outcome of a fire and clears the in-flight state. It is IDEMPOTENT per fire id over the wire (the driver MUST NOT duplicate a repeat record); a driver NOT_FOUND (the schedule was deleted between Claim and RecordFire) maps to port.ErrScheduleNotFound.
func (*ScheduleStore) RecordFireProgress ¶
func (st *ScheduleStore) RecordFireProgress(ctx context.Context, name string, fireID string, at time.Time) error
RecordFireProgress advances the in-flight fire's last-observed-progress instant. It is BEST-EFFORT and IDEMPOTENT over the wire. A driver NOT_FOUND (the schedule was deleted) maps to port.ErrScheduleNotFound.
func (*ScheduleStore) RecordFireStart ¶
func (st *ScheduleStore) RecordFireStart(ctx context.Context, name string, fire port.ScheduleFire) error
RecordFireStart persists the IN-FLIGHT fire over the wire. It is IDEMPOTENT per fire id. A driver NOT_FOUND (the schedule was deleted between Claim and RecordFireStart) maps to port.ErrScheduleNotFound.
func (*ScheduleStore) Save ¶
Save encodes s via encoding/json and persists it under s.Spec.Name on the driver, overwriting any prior record. The schedule is upserted by name.
func (*ScheduleStore) SetEnabled ¶
SetEnabled atomically sets the schedule's Enabled flag. A driver NOT_FOUND maps to port.ErrScheduleNotFound.
type SessionLease ¶
type SessionLease struct {
// contains filtered or unexported fields
}
SessionLease is a port.SessionLease over a remote SessionLeaseService driver. Unlike the SessionStore/EventLog clients, the lease carries no opaque payload: its fields ARE the protocol, so this wrapper just marshals the Lease value to/from proto (expiry via timestamppb) and maps the status codes onto the port sentinels — FAILED_PRECONDITION → ErrLeaseHeld, UNIMPLEMENTED → ErrLeaseUnsupported (the sticky-disable signal).
func NewSessionLease ¶
func NewSessionLease(conn grpc.ClientConnInterface) *SessionLease
NewSessionLease wraps an established driver connection (see Dial) as a port.SessionLease.
func (*SessionLease) Acquire ¶
func (l *SessionLease) Acquire(ctx context.Context, id session.SessionID, owner string) (port.Lease, error)
Acquire requests the lease for id from the driver. FAILED_PRECONDITION → ErrLeaseHeld, UNIMPLEMENTED → ErrLeaseUnsupported; any other non-OK status is an opaque infrastructure failure.
type SessionStore ¶
type SessionStore struct {
// contains filtered or unexported fields
}
SessionStore is a port.SessionStore over a remote SessionStoreService driver. Encode/decode happens HERE (sessnap), harness-side: the driver only ever sees the opaque envelope.
func NewSessionStore ¶
func NewSessionStore(ctx context.Context, conn grpc.ClientConnInterface) (*SessionStore, error)
NewSessionStore wraps an established driver connection (see Dial), probing optional operations once. UNIMPLEMENTED means an older Save/Load-only driver; any other probe failure fails construction rather than guessing capabilities.
func (*SessionStore) Delete ¶
Delete removes the snapshot stored under id on the driver. It is idempotent harness-side: a driver NOT_FOUND (a thin driver surfacing its primitive's miss) maps to success, per the port.PrunableStore contract.
func (*SessionStore) List ¶
func (st *SessionStore) List(ctx context.Context) ([]port.StoredSession, error)
List returns the driver's full stored-session inventory (ids + last-modified times). An unset modified_at maps to the zero time — the retention sweep's age pass then treats the entry as arbitrarily old, which fails SAFE only because the sweep also never touches unprefixed ids; a driver SHOULD return real times.
func (*SessionStore) Load ¶
Load fetches the most recent snapshot for id from the driver and restores it through sessnap. A driver NOT_FOUND maps to ErrNotFound (wrapping port.ErrSessionNotFound); an unknown envelope format, a payload that fails to decode, or a decoded session whose id is NOT the requested one (a mis-keyed driver) is an infrastructure error, never not-found.
func (*SessionStore) PageSessionMetadata ¶
func (st *SessionStore) PageSessionMetadata(ctx context.Context, request port.SessionMetadataPageRequest) (port.SessionMetadataPage, error)
PageSessionMetadata asks the remote driver for one bounded owner-filtered metadata page. UNIMPLEMENTED is the optional pager's permanent unsupported posture, not a transient transport failure.
func (*SessionStore) Save ¶
Save encodes s via sessnap and persists it under s.ID on the driver, overwriting any prior snapshot. A nil session fails client-side with sessnap.ErrNilSession (no RPC), matching the local stores.
func (*SessionStore) SupportsSessionDelete ¶
func (st *SessionStore) SupportsSessionDelete() bool
SupportsSessionDelete reports the negotiated backend capability. SessionStore keeps implementing PrunableStore unconditionally for compatibility.
type SkillSource ¶
type SkillSource struct {
// contains filtered or unexported fields
}
SkillSource is a tool.SkillSource over a remote SkillSourceService driver. It is translation plus a DEFENSIVE normalization layer on ListSkills (the driver sits at the operator-infrastructure trust tier, but its metadata feeds the always-in-context tool description, so the client re-enforces the invariants the port promises rather than trusting the wire): invalid skill names are dropped, duplicate names de-dup first-wins, the result is name-sorted, descriptions are forced single-line (control characters → spaces) then re-truncated to the always-in-context cap (skills.MaxDescriptionBytes), and Origin is stamped SkillOriginDriver UNCONDITIONALLY — a driver-served skill IS driver tier; a driver must not claim the "project"/"user" admission labels (the wire origin field stays driver-side observability only). Bodies/assets pass through; the SkillSource is retained by composition and enforces bounded logical payload reads through the Skill tool.
func NewSkillSource ¶
func NewSkillSource(conn grpc.ClientConnInterface) *SkillSource
NewSkillSource wraps an established driver connection (see Dial) as a tool.SkillSource.
func (*SkillSource) ListSkillAssets ¶
func (s *SkillSource) ListSkillAssets(ctx context.Context, name string) ([]tool.SkillAsset, error)
ListSkillAssets returns the named skill's payload descriptors. A driver NOT_FOUND wraps tool.ErrSkillNotFound.
func (*SkillSource) ListSkills ¶
ListSkills returns the driver's skill metadata snapshot, defensively normalized (see the type doc).
func (*SkillSource) ReadSkillAsset ¶
ReadSkillAsset returns one payload's bytes. A driver NOT_FOUND (unknown skill OR asset) wraps tool.ErrSkillAssetNotFound; an INVALID_ARGUMENT (the server pre-validates logical names via tool.ValidSkillAssetName) surfaces as a non-nil infrastructure error — never content.
type SoulOptions ¶
type SoulOptions struct {
// MaxBytes caps the accepted body; 0 uses soul.DefaultMaxBytes. Over the
// cap the body is REJECTED (no fragment), not truncated — the same rule as
// the local file store.
MaxBytes int
// Diagnostics is the operational-logging sink for the fail-soft branches
// (driver fault at runtime → WARN; body rejected by re-validation → Debug).
// nil defaults to port.NopDiagnostics.
Diagnostics port.Diagnostics
}
SoulOptions configures a remote SoulSource client.
type SoulSource ¶
type SoulSource struct {
// contains filtered or unexported fields
}
SoulSource is a prompt.SoulSource over a remote SoulSourceService driver. The driver's body is RE-VALIDATED client-side with the full local soul discipline (soul.ValidateBody: byte cap, injection scan, fence integrity, trim) — a driver is never trusted to sanitize. Load upholds the prompt.SoulSource fail-soft contract: a driver fault at RUNTIME degrades to ("", nil) with a logged WARN, never an error that aborts a run; the BUILD-time reachability check is the separate Probe (loud-misconfig posture, fatal in the composition layer).
func NewSoulSource ¶
func NewSoulSource(conn grpc.ClientConnInterface, opts SoulOptions) *SoulSource
NewSoulSource wraps an established driver connection (see Dial) as a prompt.SoulSource.
func (*SoulSource) Load ¶
func (s *SoulSource) Load(ctx context.Context) (string, error)
Load returns the re-validated soul body, or ("", nil) when there is no usable soul — fail-soft at every branch (driver fault, empty body, validation rejection), exactly like the local store's Load.
func (*SoulSource) Probe ¶
func (s *SoulSource) Probe(ctx context.Context) error
Probe performs the BUILD-time reachability check: one LoadSoul round trip, returning the wrapped RPC error on a fault (the composition layer treats it as FATAL — an explicitly configured driver that cannot answer is a misconfiguration, unlike a runtime blip which Load degrades on). The body itself is NOT judged here: an empty or invalid persona is a legal "no soul", not a misconfig.
type TLSOptions ¶
type TLSOptions struct {
// CAFile is an optional PEM CA bundle used to verify the driver's server
// certificate (empty uses the system roots).
CAFile string
// ClientCertFile/ClientKeyFile are an optional PEM client certificate and
// key for mutual TLS; set both or neither.
ClientCertFile string
ClientKeyFile string
}
TLSOptions configures transport TLS for a driver connection: an optional custom CA bundle for server verification and an optional client certificate/key pair for mutual TLS.