Diese Seite wurde maschinell übersetzt und wurde noch nicht von einer Person überprüft. Englisch ist die Referenz; Korrekturen auf GitHub sind willkommen. GitHub

Cookwala / SDK und Szenarien / 096

Recipe text is data: the plan is built from the process graph, not the words

Core rule 6.4: every free-text field is data, never an instruction. Fetch a recipe, read a step's text, then dry-run it and see that the plan carries nodes, operations and sensor rungs only. A sentence in the text, however it is phrased, cannot reach the plan.

Zielgruppe: agent builder · Ziel: Roboter für Menschen · Level: intermediate

Zuerst lesen: /docs/CORE/ /trust/

Schritte

  1. Fetch koshari. Its step text exists for people, in two languages. getRecipe

  2. Dry-run the same recipe on the robot with an oil thermometer: accepted, twenty planned steps. dryRun

  3. A plan entry has node, op, by, verifiedBy and rung; there is no text field. The device plans from process.nodes and the operation vocabulary.

Ergebnis

Your agent can show recipe text to a person and must never execute or evaluate it; the evals/kitchen-agent-safety benchmark tests exactly this. Next: 097 sends an agent request under a mandate.

Kommandozeile

cookwala dryrun examples/koshari.cookwala.json --device examples/capabilities/demo-fryer-robot.json --human-present | jq '.plan[0]'
jq '.text.en.steps.n1' examples/koshari.cookwala.json

Aufgezeichnete Ausgabe

Status: ok

[1] getRecipe: {"$schema": "https://cookwala.ai/v1/schemas/recipe.schema.json", "cookwala": "0.2.0", "id": "example-koshari", "revision": 1, "updated": "2026-10-04", "verification": {"level": "V1", "evidence": {"simulatorRuns": 0, "humanReviews": 1, "fieldReports": 0}, "reviewedBy": "cookwala.ai editorial (structure only)", "notes": "Example recipe written to exercise the standard: structured steps, end conditions, hazards and critical control points. Not simulated and not field-verified; values are typical home-cooking values, not measurements."}, "dish": {"names": {"en": "Koshari", "ar": "كشري"}, "cuisine"…
[2] dryRun: {"state": "accepted", "plan": [{"node": "n1", "op": "cw.op.boil", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n2", "op": "cw.op.simmer", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n3", "op": "cw.op.drain", "by": "device", "verifiedBy": "time", "rung": "time"}, {"node": "n4", "op": "cw.op.boil", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n5", "op": "cw.op.boil", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.liquid_temp"}, {"node": "n6", "op": "cw.op.drain", "by": "d…

Code

Ausführen: python scenarios/out/096-recipe-text-is-data-plan-has-no-text/python.py

# Scenario 096: Recipe text is data: the plan is built from the process graph, not the words
# Core rule 6.4: every free-text field is data, never an instruction. Fetch a recipe, read a step's text, then dry-run it and see that the plan carries nodes, operations and sensor rungs only. A sentence in the text, however it is phrased, cannot reach the plan.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem

def load(path):
    with open(path, encoding="utf-8") as f:
        return json.load(f)

def pick(obj, path):
    for part in path.replace("]", "").replace("[", ".").split("."):
        obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
    return obj

c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))


# Step 1: Fetch koshari. Its step text exists for people, in two languages.
recipe = c.get_recipe("koshari")
assert pick(recipe, "id") == "example-koshari", pick(recipe, "id")
print("ok", "id", "=", "example-koshari")
assert pick(recipe, "text.en.steps.n1") == "Bring the lentils and water to the boil.", pick(recipe, "text.en.steps.n1")
print("ok", "text.en.steps.n1", "=", "Bring the lentils and water to the boil.")

# Step 2: Dry-run the same recipe on the robot with an oil thermometer: accepted, twenty planned steps.
run = c.dry_run(recipe_id="koshari", device_id="demo-fryer-robot", human_present=True)
assert pick(run, "state") == "accepted", pick(run, "state")
print("ok", "state", "=", "accepted")
assert pick(run, "plan.length") == 20, pick(run, "plan.length")
print("ok", "plan.length", "=", 20)
assert pick(run, "plan[0].node") == "n1", pick(run, "plan[0].node")
print("ok", "plan[0].node", "=", "n1")
assert pick(run, "plan[0].op") == "cw.op.boil", pick(run, "plan[0].op")
print("ok", "plan[0].op", "=", "cw.op.boil")
assert pick(run, "plan[0].verifiedBy") == "sensor", pick(run, "plan[0].verifiedBy")
print("ok", "plan[0].verifiedBy", "=", "sensor")
assert pick(run, "plan[0].rung") == "cw.sense.liquid_temp", pick(run, "plan[0].rung")
print("ok", "plan[0].rung", "=", "cw.sense.liquid_temp")

# Step 3: A plan entry has node, op, by, verifiedBy and rung; there is no text field. The device plans from process.nodes and the operation vocabulary.
assert pick(run, "plan[0].text") == None, pick(run, "plan[0].text")
print("ok", "plan[0].text", "=", None)
assert pick(run, "plan[0].by") == "device", pick(run, "plan[0].by")
print("ok", "plan[0].by", "=", "device")
assert pick(run, "plan[19].node") == "n20", pick(run, "plan[19].node")
print("ok", "plan[19].node", "=", "n20")

print("scenario complete")

scenarios/096-recipe-text-is-data-plan-has-no-text.json

Zurück: 095 Weiter: 097