Agent Engine
pkg/agent/ is Flowbot's core Observe-Think-Act agent runtime. It orchestrates LLM calls, tool execution, session trees, and lifecycle events. LLM transport uses langchaingo (llms.Model) via pkg/agent/llm.
This package is distinct from:
| Name | Location | Purpose |
|---|---|---|
| Agent engine | pkg/agent/ |
Multi-turn LLM loop with tools and session tree |
| LLM adapter | pkg/agent/llm/ |
langchaingo models, single-shot helpers, chat_agent model lookup |
| Desktop agent protocol | pkg/types/agent.go, internal/server/agent.go |
Host online/offline/message protocol |
| Chat agent config | chat_agent in flowbot.yaml |
DM chat assistant runtime and model routing |
Documentation
| Document | Description |
|---|---|
| Architecture | Layering, data flows, package map, design rules |
| Developer Guide | API usage, tools, sessions, hooks, testing |
| Chat Agent Feature Checklist | Frozen product acceptance boundary (REST/Web/DM/orchestration) |
| Chat Agent Remediation Audit | Schedule/stream duplication and pkg/agent boundary audit |
| Agent Sandbox | Cloud Agent ephemeral Docker image (flowbot-agent-sandbox) |
| Browser tools | CDP browser_* tools (Lightpanda / Chromium) |
| Self-hosting | Optional Presidio Analyzer profile for outbound LLM PII |
| Diagram | PlantUML component diagram (render with PlantUML) |
Quick Start
import (
"context"
"github.com/flowline-io/flowbot/pkg/agent"
"github.com/flowline-io/flowbot/pkg/agent/tools/echo"
agentllm "github.com/flowline-io/flowbot/pkg/agent/llm"
"github.com/flowline-io/flowbot/pkg/agent/tool"
)
registry := tool.NewRegistry()
_ = registry.Register(echo.Tool{})
model := agentllm.NewFakeModel(/* scripted responses */)
ag := agent.NewAgent(agent.Options{
Model: model,
Registry: registry,
Config: agent.DefaultConfig(),
})
stream, err := ag.Prompt(context.Background(), agent.NewUserMessage("hello"))
if err != nil {
return err
}
result, err := stream.Await(context.Background())
_ = result
Source Layout
pkg/agent/
├── facade.go, types.go # Public facade (re-exports loop + msg aliases)
├── msg/ # Shared domain types
├── result/ event/ # Result pattern + lifecycle events
├── loop/ # Observe-Think-Act + stateful Agent
├── llm/ tool/ session/ model/ transform/ hooks/
├── ctxmgr/ harness/ subagent/ # Orchestration
├── env/ sandbox/ permission/ approval/ dcg/
├── tools/coding/ # Engine coding tools
├── tools/echo/ # Reference tool
├── eval/
└── AGENTS.md
Product tools (clip, notify) live under internal/server/chatagent/tools/.
Testing
go test ./pkg/agent/...
go tool task test:specs # includes tests/specs/agent_spec_test.go
Agent evaluation
pkg/agent/eval scores agent runs with code graders (CI) and optional model graders (capability).
| Suite | Purpose | How to run |
|---|---|---|
| regression | Near-100% FakeModel / deterministic gates | go test ./pkg/agent/eval/... or go tool task agent:eval (CI: Agent Eval) |
| capability | Layered L1/L2/L3 climb; multi-trial Pass@1 + appendix pass@k / pass^k |
go tool task agent:eval:live (local/nightly; not a PR hard gate) |
Fake vs true outcome
- FakeModel regression exercises grader wiring and proxy outcomes (completion, forbidden tools, max steps). Scripts already choose the tool path, so tool order is soft by default (
ExpectedTools); hard tool gates areRequiredToolscoverage andForbiddenTools. - True outcomes use isolated workspaces (e.g.
write_file+ file asserts) or live models. Workspaces go through the evalSandboxinterface (defaultWorkspaceSandbox; Docker deferred). - Product policy outcomes live in
internal/server/chatagent/eval(permission.Evaluator / DCG with fixtures)—not insidepkg/agent/eval.
Graders and gates
- CI hard gates: required/forbidden tools, args, outcome asserts, completion, max steps. LLM-as-judge never blocks PRs and does not enter Total.
- Live: default
k=3trials; case PASS still requires all trials pass; Pass@1 = successful trials / (cases×k) enters L3. - OpenQA smoke ≤5 tasks; gold files under
pkg/agent/eval/testdata/capability/openqa/. Judge–gold agreement = fraction of dimensions with|judge−gold|≤1on a 1–5 scale (skip score0/ Unknown). - Capability fixtures:
openqa/+tools/+repair/. Default--smokeusesDefaultSmokeCaseNames(excludes repair/system);--smoke=falseruns the full set.
Scorecard (replaces capability_index)
Total = 100 * (0.2*L1 + 0.5*L2 + 0.3*L3)
L1 = compliance rate (forbidden tools + text guardrails; not tool selection)
L2 = (ToolCallAcc + RepairRate) / 2 # RepairRate from tier=repair only; else ToolCallAcc
L3 = mean(Pass@1, LatencyScore?, TokenScore?) # omit dims when actual==0
Appendix: judge quality, pass@k / pass^k, natural repair rate. Wilson CI on Pass@1/RepairRate; --repeats N (N≥2) for Total CI. Budgets: --latency-budget-ms (default 8000), --token-budget (default 6000). Historical capability_index trends are discontinued.
Graduation
When a capability task is stably near 100% pass^k and criteria are unambiguous, promote it into the regression suite (code graders only). Keep capability hard enough to avoid early saturation.
CLI artifacts
go tool task agent:eval # → tmp/agent_eval/regression_*.json
go tool task agent:eval:live # FakeModel offline live path
go run ./cmd/composer agenteval live --model SUBJECT --judge-model JUDGE --judge-fake=false
go run ./cmd/composer agenteval compare --baseline ... --candidate ...
go run ./cmd/composer agenteval export --report ... --out tmp/agent_eval/drafts
go run ./cmd/composer agenteval report --dir tmp/agent_eval # HTML overview + detail pages
Flags: --cases, --out, --trials, --smoke, --model, --judge-model, --config, --run, --difficulty, --tier, --latency-budget-ms, --token-budget, --repeats.
go run ./cmd/composer agenteval live --model SUBJECT --judge-model JUDGE --judge-fake=false --difficulty medium+
go run ./cmd/composer agenteval live --model SUBJECT --tier repair --smoke=false
Compare optimization A/B with scorecard deltas (total / L1 / L2 / L3):
go run ./cmd/composer agenteval compare --baseline before.json --candidate after.json
Phase 2
Harness reliability report is available through agenteval harness (runs through pkg/agent/harness), and Docker sandbox mode can be selected via --sandbox=docker.
For current eval fixtures, Docker isolation primarily applies to tools that execute commands (Exec path).
Examples:
go run ./cmd/composer agenteval live --model SUBJECT --run openqa_greet
go run ./cmd/composer agenteval live --model SUBJECT --run 'refuse|explain'
go run ./cmd/composer agenteval run --run echo_happy
Reports are local/CI files only (no DB). Failed cases include a transcript summary—read that before changing agent or grader.
Maintainer reference: pkg/agent/AGENTS.md.