droid

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Jul 7, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

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

View Source
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

View Source
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.

View Source
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 New

func New(opts ...Option) (*Adapter, error)

New constructs an Adapter.

func (*Adapter) Capabilities

func (*Adapter) Capabilities() agent.Caps

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) Ref

func (*Adapter) Ref() string

Ref returns the agent-runtime identifier this adapter satisfies.

func (*Adapter) RequiredEnv

func (*Adapter) RequiredEnv() []string

RequiredEnv implements agent.CredentialNamer. Returns the CREDENTIAL env var name droid authenticates with. FACTORY_API_KEY is defined in DefaultEnvAllowlist.

func (*Adapter) ValidateConfig

func (a *Adapter) ValidateConfig(with ir.RawConfig) error

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.

func (*Adapter) Version

func (a *Adapter) Version(ctx context.Context, handle container.Handle) (string, error)

Version runs `droid --version` inside handle and parses the leading semver. Recorded in run.started.Runtimes; re-resolved on resume; drift hard-errors.

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

type ErrRuntimeNotFound struct {
	Ref       string
	Container string
	Cause     error
}

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

type ErrStreamParse struct {
	Line  []byte
	Cause error
}

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

type ErrUnexpectedExit struct {
	ExitCode int
	Stderr   string
}

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

func WithBackend(b container.Backend) Option

WithBackend supplies the container.Backend used by Version and Launch.

func WithEnv

func WithEnv(env map[string]string) Option

WithEnv supplies the env-var allowlist forwarded into each `droid exec` exec environment. Copied into agent.SecretEnv (redacts under fmt verbs; json:"-" so secrets never reach the state log). Empty map permitted.

Jump to

Keyboard shortcuts

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