sparrow-pico-rover-v1.1
- Input
- sensor numbers, flags, enums
- Runs on
- any microcontroller
- ESP32-S3
- 9.3 µs per decision
- Laptop
- 0.18 µs
- Quality
- 94.0% vs the spec's rules (its 2B teacher: 94.2%)
Tiny decision models for agents, robots and microcontrollers. From 47 MB on a laptop to ~2 KB on a chip, with calibrated answers in the same shapes as Strands Decider.
pip install sparrow-decider9.3 µs per decision on a $10 ESP32-S3. No GPU, no network, no model server.
Unofficial community project. Not an AWS or Strands product.
Probabilities computed with the released models; the C runtime on the ESP32-S3 gives the same answers. Times are measured on the board. See Benchmarks.
Measured on an ESP32-S3 at 240 MHz and on a laptop. Every figure is on the Benchmarks page with its conditions.
Pick the smallest model that fits your input and your hardware.
Most decisions in an agent or a robot have a short list of answers. Sparrow answers them about a state you give it, with calibrated probabilities, in the same shapes as Strands Decider.
noul"Is the user upset?" A probability you can threshold.
choice"Which skill should run?" A choice from your list, with a probability for each option.
score"How urgent is this?" A rating on the scale you define.
from sparrow_decider import Decider
d = Decider.load() # bundled nano model
tools = {
"flights": "search and book flights",
"refunds": "refund a payment",
"weather": "forecasts for a city",
"calendar": "create or move meetings",
}
answer = d.ask(
"User: I was charged twice, I want my money back",
{"tool": {"type": "choice",
"instructions": "Which tool fits?",
"criteria": tools}},
)["tool"]
print(answer["choice"], answer["confidence"])
# refunds 0.97pip install sparrow-decider
sparrow-decider models
sparrow-decider ask "battery: 6%\nfront_obstacle_m: 7.0" --model nano-robot \
--choice "What next?" -o "continue=keep going" -o "dock=go charge" -o "stop=halt"
sparrow-decider serve --port 8000 # POST /v1/systemone#include "sparrow.h"
static sparrow_model m;
static sparrow_ctx ctx; /* working memory; keep it static */
sparrow_load(&m, blob, blob_len);
float p_true = sparrow_noul(&m, &ctx, "motor_temp_c: 96\nmax_temp_c: 80", "Is the motor overheating?");
float conf;
int k = sparrow_choice(&m, &ctx, state, "Which skill?", opts, n_opts, &conf);
float level = sparrow_score(&m, &ctx, state, "How urgent?", levels, n_levels, &conf);#include "sparrow.h"
extern const uint8_t model_start[] asm("_binary_model_spb_start");
extern const uint8_t model_end[] asm("_binary_model_spb_end");
static sparrow_model model;
static sparrow_ctx ctx;
void app_main(void) {
sparrow_load(&model, model_start, model_end - model_start);
sparrow_option opts[] = {{"pick", "pick up an object"}, {"navigate", "move somewhere"},
{"speak", "answer the person"}};
float conf;
int k = sparrow_choice(&model, &ctx, "operator: bring me the red mug", "Which skill?", opts, 3, &conf);
}{
"name": "greenhouse",
"context": "open vents when it is above 30 C; water when soil moisture is below 25%; never water and vent at the same time in frost.",
"features": [
{"name": "temp_c", "type": "number", "min": -10, "max": 50},
{"name": "soil_moisture", "type": "number", "min": 0, "max": 100, "unit": "%"},
{"name": "raining", "type": "bool"},
{"name": "time_of_day", "type": "enum", "values": ["night", "morning", "afternoon", "evening"]}
],
"questions": {
"action": {"type": "choice", "instructions": "What should the controller do now?",
"criteria": {"nothing": "no change", "water": "start watering",
"vent": "open the vents", "heat": "turn on the heater"}},
"alert": {"type": "noul", "instructions": "Should the grower be alerted?"},
"stress": {"type": "score", "instructions": "How stressed are the plants?",
"criteria": ["fine", "mild", "severe"]}
}
}#include "sparrow_pico_greenhouse.h"
greenhouse_state s = {.temp_c = 34.0f, .soil_moisture = 40.0f, .raining = 0,
.time_of_day = GREENHOUSE_TIME_OF_DAY_AFTERNOON};
float p[GREENHOUSE_ACTION_N];
greenhouse_action(&s, p); /* probabilities over the options */nano reads text and answers any question you pose at runtime. pico has no text and no vocabulary: you describe your device's sensors and questions, and get C.
Many devices use both: pico in the control loop, nano for anything said or written.
On the ESP32-S3: int8 SIMD on the vector unit (ESP-NN kernel), weights in PSRAM / internal RAM.
First on-chip build vs today, same board. Today's nano models also use a smaller hidden layer. Each row has its own scale. Board: ESP32-S3 (QFN56 rev0.2), 240 MHz, 16 MB flash, 8 MB PSRAM.
| Model | Time per decision on ESP32-S3, first build to today |
|---|---|
| sparrow-pico-rover-v1.1 | 42.9 µs → 9.3 µs |
| sparrow-nano-general-v1.1 | 9.6 ms → 3.8 ms |
| sparrow-nano-robot-v1.2 | 73.5 ms → 3.5 ms |
The C runtime matches the Python runtime to within 1e-5 on the host; on the ESP32-S3, int8 builds agree with the host on 150-155 of 155 decisions.
pip install sparrow-decider. numpy only.
No malloc, model read from flash. Ships as an ESP-IDF component.
Write a device spec, get a C header.
Sparrow is for fixed-answer decisions about a known kind of state. We publish the misses next to the wins.
Open-ended language it never trained on: well behind the 2B (MASSIVE domain routing 0.37-0.67 across released Sparrow models vs 0.86).
Yes/no judgement on JevBench is near chance at every tier.
pico answers only the questions it was compiled for.
A pico model is as good as its teacher on your spec, and no better. Never use a learned model as the only safety stop.
Keep an LLM or a full decider for open-ended reasoning. Use confidence to fall back to it.
Install in one line, or flash a model to a $10 board.
pip install sparrow-decider