Esta página foi traduzida por máquina e ainda não foi revisada por uma pessoa. O inglês é a referência; correções são bem-vindas no GitHub. GitHub
Cookwala / SDK e cenários / 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.
Leia primeiro: /docs/CORE/ /trust/
Passos
Fetch koshari. Its step text exists for people, in two languages.
getRecipeDry-run the same recipe on the robot with an oil thermometer: accepted, twenty planned steps.
dryRunA plan entry has node, op, by, verifiedBy and rung; there is no text field. The device plans from process.nodes and the operation vocabulary.
Resultado
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.
Linha de comando
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.jsonSaída gravada
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…Código
Executar: 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")