Agent as an injectable driver
✓ LANDED
The agent core is now an independently launchable module via Bridge/Driver pattern.
The design
Agent core = independently launchable module via Bridge/Driver.
The abstraction lives in backend/agentcore/ (deliberately OUTSIDE internal/):
driver.go: defines theDriverinterface with methods:Persona,Skill,RunSkill,ExtMCPURL,Plugins,SearchCorpus,ListCorpus,GetCorpus,Resolve- Agent core is the Abstraction;
Driveris the Implementor
- Agent core is the Abstraction;
bridge.go: adapts anyDriveronto the loop's internal ports (driverSandbox→sandbox.Runner,driverSkillGetter,driverMCPGetter,driverResolver→ credential resolver)agentcore.go: public facade over the eino loop types- Launch handle:
BuildVisitorAgent(ctx, d Driver, in *LaunchInput)(visitor_build.go:50)
The proof it's real
eval-harness/ is a SEPARATE Go module whose EvalDriver (eval_driver.go) implements the interface and runs the REAL eino loop on canned data:
golden_assembly_test.go(golden-path scenarios)plugin_assembly_test.go/booker_assembly_test.go(plugin-specific tests)retrieval_assembly_test.go(retrieval / corpus tests)launch_test.go(end-to-end) + the*_live_test.goset on a real model
Only eval launches through the handle today — "eval is just another consumer" holds in the type system, not yet in prod: as of 2026-09-07 (36789537d) BuildVisitorAgent has exactly one non-test caller (eval-harness/main.go:164, candidate.go:138), and no package under backend/internal or backend/cmd imports agentcore. The prod web path is internal/routes/public/sessions.go → capreg.AssembleVisitorBundle → inference.RunAgentTurn. The intended end state — prod passes a prod Driver, eval passes an EvalDriver — is the "Remaining" item below.
Iron rules
- Re-export of
internal/types = a dependency, forbidden. Callers import onlyagentcore. - Fixtures live ONLY in the caller (
eval-harness). Backend stays fixture-free. - Guarded by
check-no-mock: ensures no mock/fixture code creeps into backend.
Class view — the textbook Bridge
classDiagram
class Driver {
<<interface - the Implementor>>
+Persona(ctx) (Persona, error)
+Skill(ctx) (*VisitorSkillSpec, error)
+RunSkill(ctx, SkillRun) (SkillResult, error)
+ExtMCPURL(ctx) (string, error)
+Plugins(ctx) ([]PluginSpec, error)
+SearchCorpus(ctx, query) ([]CorpusHit, error)
+ListCorpus(ctx, parentPath, page) ([]CorpusHit, error)
+GetCorpus(ctx, path) (CorpusDoc, error)
+Resolve(ctx) (Cred, error)
}
class LaunchInput {
OwnerID string
Mode string
ConversationID string
CodeID string
SystemPromptOverride string
GrantedCapabilities []string
}
class VisitorAgent {
Labels map[string]string
ReturnDirectly map[string]bool
SystemPrompt string
Tools []tool.BaseTool
}
class bridgeAdapters {
bridge.go - driverSandbox / driverSkillGetter / driverMCPGetter / driverResolver
wrap a Driver into the loop's internal ports
}
class EvalDriver {
eval-harness, separate go.mod
canned data behind the interface
}
class BuildVisitorAgent {
<<launch handle>>
takes ctx, Driver, *LaunchInput
returns (*VisitorAgent, error)
}
bridgeAdapters ..> Driver : wraps
Driver <|.. EvalDriver
BuildVisitorAgent ..> Driver : consumes any
BuildVisitorAgent ..> LaunchInput : input
BuildVisitorAgent --> VisitorAgent : builds
Prod and eval are meant to differ by one constructor argument — that is the whole pattern (today only the eval side of it is wired; see above).
Earlier deviation (remediated)
The earlier deviation (fixture files welded into backend/agentcore/) has been REMEDIATED — the directory is fixture-free; canned data lives only behind the injected Driver ("the Driver IS the environment").
Remaining (roadmap layer③)
Promote inject-and-launch from test-only to first-class runtime: parallel prompt experiments — the missing "quality half" of eight-controls-applied.
See also: entry-agnostic-agent (inward/outward symmetry); eval-harness-on-prod-loop (historical context).