Documentation
¶
Overview ¶
Package droid implements agent.Adapter against Factory AI's `droid` CLI (the `droid exec` non-interactive subcommand). It mirrors agent/claude; the agent package itself stays import-free of harness specifics.
Capabilities().NativeSchema is FALSE: droid has no native JSON-schema flag. The adapter runs `droid exec -o stream-json`, parses a JSON object out of the terminal "completion" event's finalText into a map, and the engine re-validates it against the step's output_schema (engine/schema.go ValidateOutputMap). This is the spec §4.2 layer-2 path (conformance Bucket 15).
Gate independence is enforced structurally: every Launch is a fresh `droid exec`; the command line NEVER contains --session-id / --resume / --fork; ValidateConfig rejects with-keys session_id/resume/fork/continue.
Output: `droid exec -o stream-json` emits newline-delimited JSON events PROGRESSIVELY as the agent works (system/message/tool_call/tool_result, then a terminal "completion" or "error"). Launch scans those lines and emits one AgentEvent per line as droid produces it (the realtime tap renders them live), capturing the terminal completion/error for the AgentOutcome. γ contract: returns immediately with both channels open; events closes before outcome.
Index ¶
- Constants
- Variables
- type Adapter
- func (*Adapter) Capabilities() agent.Caps
- func (a *Adapter) Launch(ctx context.Context, handle container.Handle, inv agent.AgentInvocation) (<-chan agent.AgentEvent, <-chan agent.AgentOutcome, error)
- func (*Adapter) Ref() string
- func (*Adapter) RequiredEnv() []string
- func (a *Adapter) ValidateConfig(with ir.RawConfig) error
- func (a *Adapter) Version(ctx context.Context, handle container.Handle) (string, error)
- type ErrMissingAPIKey
- type ErrRuntimeNotFound
- type ErrSessionReuseAttempted
- type ErrStreamParse
- type ErrUnexpectedExit
- type Option
Constants ¶
const AdapterRef = "factory/droid"
AdapterRef is the agent-runtime identifier this package's Adapter returns from Ref(). Must match the workflow `uses:` literal byte-for-byte.
Variables ¶
var DefaultEnvAllowlist = []string{
"FACTORY_API_KEY",
}
DefaultEnvAllowlist is the canonical set of env-var names the droid adapter reads. Single source of truth for the CLI's --agent-env default and resume's implicit allowlist. droid authenticates headlessly only via FACTORY_API_KEY.
var ErrAuthFailureSentinel = errors.New("agent/droid: droid exec reported an authentication failure")
ErrAuthFailureSentinel marks a droid terminal "error" event whose message names auth/FACTORY_API_KEY ("set a valid FACTORY_API_KEY"). Launch wraps it as PERMANENT (agent.ErrPermissionDenied → permanent_failure): the message is a deterministic bad/missing-key signal, so retrying only burns the budget; transient auth-infra faults surface as 5xx/timeouts on the other retryable paths instead. Consistent with the claude and awf/llm adapters.
Functions ¶
This section is empty.
Types ¶
type Adapter ¶
type Adapter struct {
// contains filtered or unexported fields
}
Adapter is the agent.Adapter implementation for Factory droid. One Adapter per CLI invocation; multiple Launch calls per Adapter; all state read-only after construction (no session state crosses Launch boundaries).
func (*Adapter) Capabilities ¶
Capabilities returns Caps{NativeSchema: false} — droid structures output via the layer-2 path; the engine validates conformance.
func (*Adapter) Launch ¶
func (a *Adapter) Launch(ctx context.Context, handle container.Handle, inv agent.AgentInvocation) (<-chan agent.AgentEvent, <-chan agent.AgentOutcome, error)
Launch runs `droid exec -o stream-json ...` inside handle via the streaming Backend.Exec. -o stream-json emits NDJSON flushed LIVE (verified v0.138.0: a system/init line, message lines, tool_call/tool_result lines, then a terminal "completion" — or a terminal "error"). Launch scans those lines and emits ONE AgentEvent per line as it arrives (the realtime tap renders these live), capturing the terminal completion/error for the AgentOutcome. γ contract: returns IMMEDIATELY with both channels open; events closes BEFORE outcome (defer LIFO); never reuses a session.
func (*Adapter) RequiredEnv ¶
RequiredEnv implements agent.CredentialNamer. Returns the CREDENTIAL env var name droid authenticates with. FACTORY_API_KEY is defined in DefaultEnvAllowlist.
func (*Adapter) ValidateConfig ¶
ValidateConfig enforces droid's with-schema (same deterministic order as claude: reject-inline/session → unknown-key → required-prompt → per-key types → BYOK-or-API-key policy). Deterministic (sorted keys) — runs twice per node.
type ErrMissingAPIKey ¶
type ErrMissingAPIKey struct {
AvailableKeys []string
}
ErrMissingAPIKey is returned by ValidateConfig when FACTORY_API_KEY is absent from the adapter's env allowlist. droid has no headless auth fallback, so we fail at the run-start walk with an actionable message.
func (*ErrMissingAPIKey) Error ¶
func (e *ErrMissingAPIKey) Error() string
type ErrRuntimeNotFound ¶
ErrRuntimeNotFound is returned by Version when `droid --version` failed.
func (*ErrRuntimeNotFound) Error ¶
func (e *ErrRuntimeNotFound) Error() string
func (*ErrRuntimeNotFound) Unwrap ¶
func (e *ErrRuntimeNotFound) Unwrap() error
type ErrSessionReuseAttempted ¶
type ErrSessionReuseAttempted struct {
Key string
}
ErrSessionReuseAttempted is returned by ValidateConfig when a with-key names a flag that would re-use a prior droid session (session_id / resume / fork / continue). Gate independence (spec §5.5) is engine-enforced, not convention.
func (*ErrSessionReuseAttempted) Error ¶
func (e *ErrSessionReuseAttempted) Error() string
type ErrStreamParse ¶
ErrStreamParse is returned by parseStreamEvent when a stdout line fails to decode as a -o stream-json event. Launch tolerates a stray non-JSON line (skips it), so this type does not itself propagate out of Launch; it backs the parse unit tests.
func (*ErrStreamParse) Error ¶
func (e *ErrStreamParse) Error() string
func (*ErrStreamParse) Unwrap ¶
func (e *ErrStreamParse) Unwrap() error
type ErrUnexpectedExit ¶
ErrUnexpectedExit is sent (bare) on Launch's outcome channel when droid exited with no parseable result envelope on stdout AND stderr matched no known config-error pattern. The engine's classifier maps unrecognized error types to retryable_failure via its default branch, so a bare ErrUnexpectedExit is treated as transport-class (retryable) without an explicit ErrAgentLaunch wrap.
func (*ErrUnexpectedExit) Error ¶
func (e *ErrUnexpectedExit) Error() string
type Option ¶
type Option func(*Adapter)
Option configures the Adapter at construction time (functional-options).
func WithBackend ¶
WithBackend supplies the container.Backend used by Version and Launch.