jevrecipes

Recipe catalog / choose-action

Choose a game action from supplied candidates

Recommend one eligible game action against a supplied goal, using rules, current state, and optional player history.

You need to choose the next game action from a list using the current environment, game rules, and previous player actions.

Explore this recipe interactively ยท Source and implementation guide

Use choose-action in TypeScript

Install with npm install jev-recipes. Requires Node.js 22.9 or newer and ES modules. Set TYPESAFE_API_KEY in your server environment for live calls, which send input to TypeSafe and use API quota. See the installation guide.

import { chooseAction } from 'jev-recipes/choose-action';

const result = await chooseAction({
  "player": "Blue",
  "objective": "Finish the final round with as many points as possible. Unused shields have no score.",
  "rules": "A challenge pauses the normal turn. The challenged player must defend by spending one shield or concede and lose two points. Defending prevents the point loss.",
  "environment": "Red's normal turn is paused while Blue answers a challenge. Blue has one shield and five points. This is the final round.",
  "actions": [
    {
      "id": "defend",
      "text": "Spend one shield to defend against the current challenge."
    },
    {
      "id": "concede",
      "text": "Accept the current challenge and lose two points."
    }
  ],
  "history": [
    {
      "player": "Red",
      "action": "Challenged Blue; the challenge is awaiting Blue's response."
    }
  ]
});
console.log(result);

Input contract

FieldTypeNeeded
playerstringRequired
objectivestringRequired
rulesstringRequired
environmentstringRequired
actionsarrayRequired
historyarrayOptional
minConfidencenumberOptional
Full input and result schemas
{
  "input": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
      "player": {
        "type": "string",
        "description": "The player whose next action should be chosen."
      },
      "objective": {
        "type": "string",
        "description": "The goal or scoring preference used to compare eligible actions."
      },
      "rules": {
        "type": "string",
        "description": "Applicable game rules, including turn, phase, resource, and action constraints."
      },
      "environment": {
        "type": "string",
        "description": "The current game snapshot available to the player, after the supplied history."
      },
      "actions": {
        "minItems": 1,
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "text": {
              "type": "string"
            }
          },
          "required": [
            "id",
            "text"
          ]
        },
        "description": "One or more candidate actions with unique IDs and concrete action descriptions."
      },
      "history": {
        "maxItems": 100,
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "player": {
              "type": "string",
              "description": "The player who took the recorded action."
            },
            "action": {
              "type": "string",
              "description": "The observed action, including its known outcome when relevant."
            }
          },
          "required": [
            "player",
            "action"
          ]
        },
        "description": "Optional observed actions by any players, oldest first. May be empty or incomplete."
      },
      "minConfidence": {
        "type": "number",
        "minimum": 0,
        "maximum": 1
      }
    },
    "required": [
      "player",
      "objective",
      "rules",
      "environment",
      "actions"
    ]
  },
  "result": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
      "model": {
        "type": "string"
      },
      "usage": {
        "type": "object",
        "properties": {
          "input_tokens": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "output_tokens": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          }
        },
        "required": [
          "input_tokens",
          "output_tokens"
        ],
        "additionalProperties": false
      },
      "status": {
        "type": "string",
        "enum": [
          "ready",
          "review"
        ]
      },
      "verdict": {
        "type": "string",
        "enum": [
          "matched",
          "none",
          "ambiguous"
        ]
      },
      "selection": {
        "type": [
          "string",
          "null"
        ]
      },
      "suggestedSelection": {
        "type": [
          "string",
          "null"
        ]
      },
      "confidence": {
        "type": "number",
        "minimum": 0,
        "maximum": 1
      },
      "probabilities": {
        "type": "object",
        "properties": {
          "candidates": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            }
          },
          "none": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "ambiguous": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          }
        },
        "required": [
          "candidates",
          "none",
          "ambiguous"
        ],
        "additionalProperties": false
      }
    },
    "required": [
      "model",
      "usage",
      "status",
      "verdict",
      "selection",
      "suggestedSelection",
      "confidence",
      "probabilities"
    ],
    "additionalProperties": false
  }
}

Saved example result

This hand-authored response demonstrates the contract. It is not a model accuracy measurement. Run it without an API key: npx jev-recipes demo choose-action.

{
  "model": "demo-fixture",
  "usage": {
    "input_tokens": 0,
    "output_tokens": 0
  },
  "status": "ready",
  "verdict": "matched",
  "selection": "defend",
  "suggestedSelection": "defend",
  "confidence": 0.94,
  "probabilities": {
    "candidates": {
      "defend": 0.94,
      "concede": 0.02
    },
    "none": 0.02,
    "ambiguous": 0.02
  }
}

Evaluation evidence

Unknown response origin

No verified live accuracy measurement is available. Evaluate representative cases before using this decision in your workflow.

Use the evaluation guide to measure this decision on your own labeled cases.

Limitations

Related recipes